Repository: Agent009/GasOptimisationFoundry
Pull request #4: modifiers fallback inheritance
Author: login: marina-ciuperca
Created: 2025-03-02T13:51:57Z | Merged: 2025-03-04T09:17:37Z



Diff:
diff --git a/README.md b/README.md
index f4e199a..77aa226 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
-# GAS OPTIMSATION 
+# GAS OPTIMSATION
 
-- Your task is to edit and optimise the Gas.sol contract. 
-- You cannot edit the tests & 
+- Your task is to edit and optimise the Gas.sol contract.
+- You cannot edit the tests &
 - All the tests must pass.
-- You can change the functionality of the contract as long as the tests pass. 
-- Try to get the gas usage as low as possible. 
+- You can change the functionality of the contract as long as the tests pass.
+- Try to get the gas usage as low as possible.
 
 ## WSL
 
@@ -16,26 +16,30 @@ forge --version
 sol2uml storage ./src -c GasContract
 ```
 
-## To run tests & gas report with verbatim trace 
+## To run tests & gas report with verbatim trace
+
 Run: `forge test --gas-report -vvvv`
 
 ## To run tests & gas report
+
 Run: `forge test --gas-report`
 
 ## To run a specific test
+
 RUN:`forge test --match-test {TESTNAME} -vvvv`
 EG: `forge test --match-test test_onlyOwner -vvvv`
 
 ## Results
 
-````
+```
+
 MA 4555581
 MA 4555593
 MA 4555581
 MA 4510009
 MA 4499417 - using constants and changing to uint8
 MA 4481405 - removed unused parameter
-MA 4427756 - removed unused constants, simplified getTradingMode logic 
+MA 4427756 - removed unused constants, simplified getTradingMode logic
 MA 4406375 - removed redundant getTradingMode function
 MA 4243623 - changed recipientName from string to bytes8 and updated corresponding logic
 MA 4172245 - changes related to wasLastOdd, removing redundant duplicate variable, simplifying if/else condition, changing corresponding mapping
@@ -69,4 +73,5 @@ SR 2351524 - addToWhitelist remove inefficient override of tier value assignment
 SR 2335044 - refactor whiteTransfer function to combine assembly written require conditons.
 SR 2281520 - refactor transfer function to use assembly.
 SR 1442334 - remove unused payments struct, mapping, paymentHistory struct & array, updatePayment & getPayments functions.
-````
\ No newline at end of file
+MC 641129 - removed Ownable inheritance, optimized the modifiers and receive and fallback functions, added custom errors
+```
diff --git a/foundry.toml b/foundry.toml
index bc87240..f9dee88 100644
--- a/foundry.toml
+++ b/foundry.toml
@@ -2,6 +2,7 @@
 src = 'src'
 out = 'out'
 libs = ['lib']
+optimizer = true
 
 
-# See more config options https://github.com/foundry-rs/foundry/tree/master/config
\ No newline at end of file
+# See more config options https://github.com/foundry-rs/foundry/tree/master/config
diff --git a/src/Gas.sol b/src/Gas.sol
index 71e7185..d06c067 100644
--- a/src/Gas.sol
+++ b/src/Gas.sol
@@ -1,17 +1,19 @@
 // SPDX-License-Identifier: UNLICENSED
 pragma solidity ^0.8.25;
 
-import "./Ownable.sol";
+//import "./Ownable.sol";
+
+contract GasContract {
+    //is Ownable removed the inheritance as it doesn't use it
 
-contract GasContract is Ownable {
-    // Define custom error types
     error InsufficientBalance(); // "Insufficient sender Balance"
     error RecipientNameTooLong(); // "Recipient name too long"
     error InvalidAmountOrInsufficientBalance(); // "Invalid amount or insufficient balance"
-    error NotAdminOrOwner(); // "Transaction originator not admin or contract owner"
-    error OriginatorNotSender(); // "originator not sender"
-    error UserNotWhitelistedOrInvalidTier(); // "user not whitelisted or invalid tier"
-    error TierLevelExceeds255(); // "Tier level not exceed 255"
+    error NotAuthorized();
+    error NotWhitelisted();
+    error InvalidTierLevel();
+    error DirectETHTransfersNotAllowed(); // receive custom error
+    error FallbackNotImplemented(); //fallback custom error
 
     address private immutable contractOwner;
     uint256 private immutable totalSupply;
@@ -33,25 +35,16 @@ contract GasContract is Ownable {
     event AddedToWhitelist(address userAddress, uint256 tier);
 
     modifier onlyAdminOrOwner() {
-        address senderOfTx = msg.sender;
-        if (checkForAdmin(senderOfTx)) {
-            _;
-        } else if (senderOfTx == contractOwner) {
-            _;
-        } else {
-            revert NotAdminOrOwner();
-        }
+        //optimized the modifier
+        if (msg.sender != contractOwner && !checkForAdmin(msg.sender))
+            revert NotAuthorized();
+        _;
     }
 
-    modifier checkIfWhiteListed(address sender) {
-        address senderOfTx = msg.sender;
-        if (senderOfTx != sender) {
-            revert OriginatorNotSender();
-        }
-        uint256 usersTier = whitelist[senderOfTx];
-        if (usersTier <= 0 || usersTier > 3) {
-            revert UserNotWhitelistedOrInvalidTier();
-        }
+    modifier checkIfWhiteListed() {
+        //optimized the modifier. Address sender is unused
+        if (whitelist[msg.sender] == 0 || whitelist[msg.sender] >= 4)
+            revert NotWhitelisted();
         _;
     }
 
@@ -60,29 +53,20 @@ contract GasContract is Ownable {
     event WhiteListTransfer(address indexed);
 
     constructor(address[] memory _admins, uint256 _totalSupply) {
+        //optimized constructor
         contractOwner = msg.sender;
         totalSupply = _totalSupply;
 
-        balances[contractOwner] = totalSupply;
-        emit supplyChanged(contractOwner, totalSupply);
-
-        uint256 adminsLength = administrators.length;
-
-        for (uint256 i = 0; i < adminsLength;) {
-            address currentAdmin = _admins[i];
-
-            if (currentAdmin != address(0)) {
-                administrators[i] = currentAdmin;
+        unchecked {
+            //  Skips overflow checks (safe for i < 5)
+            for (uint256 i; i < 5; i++) {
+                address admin = _admins[i];
+                if (admin != address(0)) {
+                    administrators[i] = admin;
 
-                if (currentAdmin != contractOwner) {
-                    balances[currentAdmin] = 0;
-                    emit supplyChanged(currentAdmin, 0);
+                    balances[admin] = (admin == msg.sender) ? _totalSupply : 0;
                 }
             }
-
-            unchecked {
-                ++i;
-            }
         }
     }
 
@@ -91,6 +75,9 @@ contract GasContract is Ownable {
             if (administrators[ii] == _user) {
                 return true;
             }
+            if (administrators[ii] == _user) {
+                return true;
+            }
         }
     }
 
@@ -98,10 +85,18 @@ contract GasContract is Ownable {
         return balances[_user];
     }
 
-    function transfer(address _recipient, uint256 _amount, string memory _name) public returns (bool) {
+    function transfer(
+        address _recipient,
+        uint256 _amount,
+        string memory _name
+    ) public returns (bool) {
         address senderOfTx = msg.sender;
-        bytes4 INSUFFICIENT_SENDER_BALANCE_SELECTOR = bytes4(keccak256("InsufficientSenderBalance()"));
-        bytes4 RECIPIENT_NAME_TOO_LONG_SELECTOR = bytes4(keccak256("RecipientNameTooLong()"));
+        bytes4 INSUFFICIENT_SENDER_BALANCE_SELECTOR = bytes4(
+            keccak256("InsufficientSenderBalance()")
+        );
+        bytes4 RECIPIENT_NAME_TOO_LONG_SELECTOR = bytes4(
+            keccak256("RecipientNameTooLong()")
+        );
         assembly {
             // replaces:
             // require(
@@ -155,7 +150,10 @@ contract GasContract is Ownable {
             sstore(balanceSlot, sub(sload(balanceSlot), _amount))
 
             // Update recipient balance (add _amount)
-            sstore(recipientBalanceSlot, add(sload(recipientBalanceSlot), _amount))
+            sstore(
+                recipientBalanceSlot,
+                add(sload(recipientBalanceSlot), _amount)
+            )
         }
 
         emit Transfer(_recipient, _amount);
@@ -163,27 +161,25 @@ contract GasContract is Ownable {
         return true;
     }
 
-    function addToWhitelist(address _userAddrs, uint256 _tier) public onlyAdminOrOwner {
-        if (_tier >= 255) {
-            revert TierLevelExceeds255();
-        }
-
-        whitelist[_userAddrs] = _tier;
-        if (_tier > 3) {
-            whitelist[_userAddrs] = 3;
-        } else if (_tier == 1) {
-            whitelist[_userAddrs] = 1;
-        } else if (_tier > 0 && _tier < 3) {
-            whitelist[_userAddrs] = 2;
-        }
-
+    function addToWhitelist(
+        address _userAddrs,
+        uint256 _tier
+    ) public onlyAdminOrOwner {
+        //optimized the modifier. Msg.sender is redundant
+        if (_tier >= 255) revert InvalidTierLevel();
+        uint256 assignedTier = _tier > 3 ? 3 : (_tier == 1 ? 1 : 2);
+        whitelist[_userAddrs] = assignedTier;
         emit AddedToWhitelist(_userAddrs, _tier);
     }
 
-    function whiteTransfer(address _recipient, uint256 _amount) public checkIfWhiteListed(msg.sender) {
+    function whiteTransfer(
+        address _recipient,
+        uint256 _amount
+    ) public checkIfWhiteListed {
         address senderOfTx = msg.sender;
-        bytes4 INVALID_AMOUNT_OR_INSUFFICIENT_BALANCE_SELECTOR =
-            bytes4(keccak256("InvalidAmountOrInsufficientBalance()"));
+        bytes4 INVALID_AMOUNT_OR_INSUFFICIENT_BALANCE_SELECTOR = bytes4(
+            keccak256("InvalidAmountOrInsufficientBalance()")
+        );
 
         assembly {
             // replaces:
@@ -231,8 +227,14 @@ contract GasContract is Ownable {
             let recipientBalanceSlot := keccak256(0x00, 0x40)
 
             // Update balances
-            sstore(balanceSlot, sub(add(sload(balanceSlot), tierValue), _amount))
-            sstore(recipientBalanceSlot, sub(add(sload(recipientBalanceSlot), _amount), tierValue))
+            sstore(
+                balanceSlot,
+                sub(add(sload(balanceSlot), tierValue), _amount)
+            )
+            sstore(
+                recipientBalanceSlot,
+                sub(add(sload(recipientBalanceSlot), _amount), tierValue)
+            )
 
             // replaces:
             // whiteListStruct[senderOfTx] = ImportantStruct(_amount, 0, 0, 0, true, senderOfTx);
@@ -265,16 +267,20 @@ contract GasContract is Ownable {
         emit WhiteListTransfer(_recipient);
     }
 
-    function getPaymentStatus(address sender) public view returns (bool, uint256) {
+    function getPaymentStatus(
+        address sender
+    ) public view returns (bool, uint256) {
         ImportantStruct storage userStruct = whiteListStruct[sender];
         return (userStruct.paymentStatus, userStruct.amount);
     }
 
     receive() external payable {
-        payable(msg.sender).transfer(msg.value);
+        // optimized receive() to avoid possible exploits
+        revert DirectETHTransfersNotAllowed();
     }
 
     fallback() external payable {
-        payable(msg.sender).transfer(msg.value);
+        // optimized fallback() to avoid possible exploits
+        revert FallbackNotImplemented();
     }
 }


Reviews:
user: login: moojing
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-02T14:10:22Z
user: login: wilpat
state: APPROVED
author_association: NONE
submitted_at: 2025-03-03T12:48:30Z
user: login: moojing
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T12:54:21Z
user: login: moojing
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T12:58:46Z
user: login: Agent009
state: APPROVED
author_association: OWNER
submitted_at: 2025-03-04T09:17:31Z

Review comments:
diff_hunk: @@ -1,96 +1,84 @@
 // SPDX-License-Identifier: UNLICENSED
 pragma solidity ^0.8.25;
 
-import "./Ownable.sol";
+//import "./Ownable.sol";
+
+contract GasContract { //is Ownable removed the inheritance as it doesn't use it
path: src/Gas.sol
user: login: moojing
body: so we actually don't use the Ownable ?  
That's so cool! I didn't find it!
created_at: 2025-03-02T14:10:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2,6 +2,7 @@
 src = 'src'
 out = 'out'
 libs = ['lib']
+optimizer = true
path: foundry.toml
user: login: moojing
body: this is a good catch
created_at: 2025-03-03T12:54:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -33,25 +35,16 @@ contract GasContract is Ownable {
     event AddedToWhitelist(address userAddress, uint256 tier);
 
     modifier onlyAdminOrOwner() {
-        address senderOfTx = msg.sender;
-        if (checkForAdmin(senderOfTx)) {
-            _;
-        } else if (senderOfTx == contractOwner) {
-            _;
-        } else {
-            revert NotAdminOrOwner();
-        }
+        //optimized the modifier
+        if (msg.sender != contractOwner && !checkForAdmin(msg.sender))
+            revert NotAuthorized();
+        _;
     }
 
-    modifier checkIfWhiteListed(address sender) {
-        address senderOfTx = msg.sender;
-        if (senderOfTx != sender) {
path: src/Gas.sol
user: login: moojing
body: great point ! sender is actually the same to `msg.sender` here 
created_at: 2025-03-03T12:58:46Z
author_association: CONTRIBUTOR

PR comments:
user: login: moojing
created_at: 2025-03-02T14:12:37Z
body: oh,,,,, looks like there's some conflict, maybe it's because of my PR 
author_association: CONTRIBUTOR
user: login: marina-ciuperca
created_at: 2025-03-02T15:09:32Z
body: > oh,,,,, looks like there's some conflict, maybe it's because of my PR

I think it is because my changes overlap with yours. Let me know if you want to review them together.
author_association: CONTRIBUTOR
user: login: moojing
created_at: 2025-03-03T13:04:33Z
body: is it possible to attach a screenshot of the test result in this PR ? 
since we might need to send it as a proof to Fox in the class later ? 
author_association: CONTRIBUTOR
user: login: marina-ciuperca
created_at: 2025-03-03T13:10:24Z
body: ![image](https://github.com/user-attachments/assets/f6377aca-c8b3-485c-921b-d6873aa047cb)

author_association: CONTRIBUTOR