implement Access Control:

contract AccessControl {
    event GrantRole(bytes32 indexed role, address indexed account);
    event RevokeRole(bytes32 indexed role, address indexed account);

    mapping(bytes32 => mapping(address => bool)) public roles;

    bytes32 public constant ADMIN = keccak256(abi.encodePacked("ADMIN"));
//can make it private and constant
    bytes32 public constant USER = keccak256(abi.encodePacked("USER"));
    
    modifier onlyRole(bytes32 _role){
        
        require(roles[_role][msg.sender]);
            _;
        
    }
    
    constructor() {
        roles[ADMIN][msg.sender] = true; 
    }
}

Hashing the name of the role to bytes32, so even the name is really long it can still fit in the bytes32, saving gas.

selfdestruct(payable(msg.sender)); ⇒ with send eth to the msg.sender as well.


deconstructing a struct (lol):

https://solidity-by-example.org/structs/

struct Transaction {
        address to;
        uint value;
        bytes data;
        bool executed;
    }

Transaction[] public transactions;

function getApprovalCount(uint _txId) private view returns(uint) {
        uint count; 
       for (uint i; i < owners.length; i++) {
           
            address owner = owners[i];
            
            if(approved[_txId][owner]){
                count++;
            }

        }
        return count;
    }
function execute(uint _txId) onlyOwner txExists(_txId) notExecuted(_txId)  external {
        
        uint approval = getApprovalCount(_txId);
        Transaction storage transaction =  transactions[_txId];
        require(approval >= required, "vote not enough"); 
        
  
        //execute the function
    
     (bool success, bytes memory data) = transaction.to.call{value: transaction.value}(
             transaction.data
        );
        
        require(success, "transaction failed");
        
         transaction.executed = true;

        //emit Execute 
       emit Execute(_txId);
    }