prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  [Bug] contract reports ether as locked when ether is sent in Yul
  The following contract reports ether as locked despite it being sent in a Yul block
  ```
  contract FPLockedEther {
    receive() payable external {}
  
    function yulSendEther() external {
      bool success;
      assembly {
        success := call(gas(), caller(), balance(address()), 0,0,0,0)
      }
    }
  }
  ```
  ```
  Contract locking ether found:
  	Contract FPLockedEther (locked-ether.sol#1-13) has payable functions:
  	 - FPLockedEther.receive() (locked-ether.sol#2-3)
  	But does not have a function to withdraw the ether
  Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#contracts-that-lock-ether
  ```
  
  It could be that the IR is incorrect here as it should not be a `SOLIDITY_CALL`
  ```
  Contract FPLockedEther
  	Function FPLockedEther.receive() (*)
  	Function FPLockedEther.yulSendEther() (*)
  		Expression: success = call(uint256,uint256,uint256,uint256,uint256,uint256,uint256)(gas()(),caller()(),balance(uint256)(address()()),0,0,0,0)
  		IRs:
  			TMP_0(uint256) = SOLIDITY_CALL gas()()
  			TMP_1(address) := msg.sender(address)
  			TMP_2 = CONVERT this to address
  			TMP_3(uint256) = SOLIDITY_CALL balance(uint256)(TMP_2)
  			TMP_4(uint256) = SOLIDITY_CALL call(uint256,uint256,uint256,uint256,uint256,uint256,uint256)(TMP_0,TMP_1,TMP_3,0,0,0,0)
  			success(bool) := TMP_4(uint256)
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `slither/detectors/attributes/locked_ether.py`
  Content:
  ```
  1 """
  2     Check if ethers are locked in the contract
  3 """
  4 from typing import List
  5 
  6 from slither.core.declarations.contract import Contract
  7 from slither.detectors.abstract_detector import (
  8     AbstractDetector,
  9     DetectorClassification,
  10     DETECTOR_INFO,
  11 )
  12 from slither.slithir.operations import (
  13     HighLevelCall,
  14     LowLevelCall,
  15     Send,
  16     Transfer,
  17     NewContract,
  18     LibraryCall,
  19     InternalCall,
  20 )
  21 from slither.utils.output import Output
  22 
  23 
  24 class LockedEther(AbstractDetector):  # pylint: disable=too-many-nested-blocks
  25 
  26     ARGUMENT = "locked-ether"
  27     HELP = "Contracts that lock ether"
  28     IMPACT = DetectorClassification.MEDIUM
  29     CONFIDENCE = DetectorClassification.HIGH
  30 
  31     WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#contracts-that-lock-ether"
  32 
  33     WIKI_TITLE = "Contracts that lock Ether"
  34     WIKI_DESCRIPTION = "Contract with a `payable` function, but without a withdrawal capacity."
  35 
  36     # region wiki_exploit_scenario
  37     WIKI_EXPLOIT_SCENARIO = """
  38 ```solidity
  39 pragma solidity 0.4.24;
  40 contract Locked{
  41     function receive() payable public{
  42     }
  43 }
  44 ```
  45 Every Ether sent to `Locked` will be lost."""
  46     # endregion wiki_exploit_scenario
  47 
  48     WIKI_RECOMMENDATION = "Remove the payable attribute or add a withdraw function."
  49 
  50     @staticmethod
  51     def do_no_send_ether(contract: Contract) -> bool:
  52         functions = contract.all_functions_called
  53         to_explore = functions
  54         explored = []
  55         while to_explore:  # pylint: disable=too-many-nested-blocks
  56             functions = to_explore
  57             explored += to_explore
  58             to_explore = []
  59             for function in functions:
  60                 calls = [c.name for c in function.internal_calls]
  61                 if "suicide(address)" in calls or "selfdestruct(address)" in calls:
  62                     return False
  63                 for node in function.nodes:
  64                     for ir in node.irs:
  65                         if isinstance(
  66                             ir,
  67                             (Send, Transfer, HighLevelCall, LowLevelCall, NewContract),
  68                         ):
  69                             if ir.call_value and ir.call_value != 0:
  70                                 return False
  71                         if isinstance(ir, (LowLevelCall)):
  72                             if ir.function_name in ["delegatecall", "callcode"]:
  73                                 return False
  74                         # If a new internal call or librarycall
  75                         # Add it to the list to explore
  76                         # InternalCall if to follow internal call in libraries
  77                         if isinstance(ir, (InternalCall, LibraryCall)):
  78                             if not ir.function in explored:
  79                                 to_explore.append(ir.function)
  80 
  81         return True
  82 
  83     def _detect(self) -> List[Output]:
  84         results = []
  85 
  86         for contract in self.compilation_unit.contracts_derived:
  87             if contract.is_signature_only():
  88                 continue
  89             funcs_payable = [function for function in contract.functions if function.payable]
  90             if funcs_payable:
  91                 if self.do_no_send_ether(contract):
  92                     info: DETECTOR_INFO = ["Contract locking ether found:\n"]
  93                     info += ["\tContract ", contract, " has payable functions:\n"]
  94                     for function in funcs_payable:
  95                         info += ["\t - ", function, "\n"]
  96                     info += "\tBut does not have a function to withdraw the ether\n"
  97 
  98                     json = self.generate_result(info)
  99 
  100                     results.append(json)
  101 
  102         return results
  103
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/slither/detectors/attributes/locked_ether.py b/slither/detectors/attributes/locked_ether.py
  --- a/slither/detectors/attributes/locked_ether.py
  +++ b/slither/detectors/attributes/locked_ether.py
  @@ -3,7 +3,7 @@
   """
   from typing import List
   
  -from slither.core.declarations.contract import Contract
  +from slither.core.declarations import Contract, SolidityFunction
   from slither.detectors.abstract_detector import (
       AbstractDetector,
       DetectorClassification,
  @@ -17,7 +17,9 @@
       NewContract,
       LibraryCall,
       InternalCall,
  +    SolidityCall,
   )
  +from slither.slithir.variables import Constant
   from slither.utils.output import Output
   
   
  @@ -68,8 +70,28 @@
                           ):
                               if ir.call_value and ir.call_value != 0:
                                   return False
  -                        if isinstance(ir, (LowLevelCall)):
  -                            if ir.function_name in ["delegatecall", "callcode"]:
  +                        if isinstance(ir, (LowLevelCall)) and ir.function_name in [
  +                            "delegatecall",
  +                            "callcode",
  +                        ]:
  +                            return False
  +                        if isinstance(ir, SolidityCall):
  +                            call_can_send_ether = ir.function in [
  +                                SolidityFunction(
  +                                    "delegatecall(uint256,uint256,uint256,uint256,uint256,uint256)"
  +                                ),
  +                                SolidityFunction(
  +                                    "callcode(uint256,uint256,uint256,uint256,uint256,uint256,uint256)"
  +                                ),
  +                                SolidityFunction(
  +                                    "call(uint256,uint256,uint256,uint256,uint256,uint256,uint256)"
  +                                ),
  +                            ]
  +                            nonzero_call_value = call_can_send_ether and (
  +                                not isinstance(ir.arguments[2], Constant)
  +                                or ir.arguments[2].value != 0
  +                            )
  +                            if nonzero_call_value:
                                   return False
                           # If a new internal call or librarycall
                           # Add it to the list to explore
  
verification_info: {"golden_diff": "diff --git a/slither/detectors/attributes/locked_ether.py b/slither/detectors/attributes/locked_ether.py\n--- a/slither/detectors/attributes/locked_ether.py\n+++ b/slither/detectors/attributes/locked_ether.py\n@@ -3,7 +3,7 @@\n \"\"\"\n from typing import List\n \n-from slither.core.declarations.contract import Contract\n+from slither.core.declarations import Contract, SolidityFunction\n from slither.detectors.abstract_detector import (\n     AbstractDetector,\n     DetectorClassification,\n@@ -17,7 +17,9 @@\n     NewContract,\n     LibraryCall,\n     InternalCall,\n+    SolidityCall,\n )\n+from slither.slithir.variables import Constant\n from slither.utils.output import Output\n \n \n@@ -68,8 +70,28 @@\n                         ):\n                             if ir.call_value and ir.call_value != 0:\n                                 return False\n-                        if isinstance(ir, (LowLevelCall)):\n-                            if ir.function_name in [\"delegatecall\", \"callcode\"]:\n+                        if isinstance(ir, (LowLevelCall)) and ir.function_name in [\n+                            \"delegatecall\",\n+                            \"callcode\",\n+                        ]:\n+                            return False\n+                        if isinstance(ir, SolidityCall):\n+                            call_can_send_ether = ir.function in [\n+                                SolidityFunction(\n+                                    \"delegatecall(uint256,uint256,uint256,uint256,uint256,uint256)\"\n+                                ),\n+                                SolidityFunction(\n+                                    \"callcode(uint256,uint256,uint256,uint256,uint256,uint256,uint256)\"\n+                                ),\n+                                SolidityFunction(\n+                                    \"call(uint256,uint256,uint256,uint256,uint256,uint256,uint256)\"\n+                                ),\n+                            ]\n+                            nonzero_call_value = call_can_send_ether and (\n+                                not isinstance(ir.arguments[2], Constant)\n+                                or ir.arguments[2].value != 0\n+                            )\n+                            if nonzero_call_value:\n                                 return False\n                         # If a new internal call or librarycall\n                         # Add it to the list to explore\n", "issue": "[Bug] contract reports ether as locked when ether is sent in Yul\nThe following contract reports ether as locked despite it being sent in a Yul block\r\n```\r\ncontract FPLockedEther {\r\n  receive() payable external {}\r\n\r\n  function yulSendEther() external {\r\n    bool success;\r\n    assembly {\r\n      success := call(gas(), caller(), balance(address()), 0,0,0,0)\r\n    }\r\n  }\r\n}\r\n```\r\n```\r\nContract locking ether found:\r\n\tContract FPLockedEther (locked-ether.sol#1-13) has payable functions:\r\n\t - FPLockedEther.receive() (locked-ether.sol#2-3)\r\n\tBut does not have a function to withdraw the ether\r\nReference: https://github.com/crytic/slither/wiki/Detector-Documentation#contracts-that-lock-ether\r\n```\r\n\r\nIt could be that the IR is incorrect here as it should not be a `SOLIDITY_CALL`\r\n```\r\nContract FPLockedEther\r\n\tFunction FPLockedEther.receive() (*)\r\n\tFunction FPLockedEther.yulSendEther() (*)\r\n\t\tExpression: success = call(uint256,uint256,uint256,uint256,uint256,uint256,uint256)(gas()(),caller()(),balance(uint256)(address()()),0,0,0,0)\r\n\t\tIRs:\r\n\t\t\tTMP_0(uint256) = SOLIDITY_CALL gas()()\r\n\t\t\tTMP_1(address) := msg.sender(address)\r\n\t\t\tTMP_2 = CONVERT this to address\r\n\t\t\tTMP_3(uint256) = SOLIDITY_CALL balance(uint256)(TMP_2)\r\n\t\t\tTMP_4(uint256) = SOLIDITY_CALL call(uint256,uint256,uint256,uint256,uint256,uint256,uint256)(TMP_0,TMP_1,TMP_3,0,0,0,0)\r\n\t\t\tsuccess(bool) := TMP_4(uint256)\r\n```\n", "before_files": [{"content": "\"\"\"\n    Check if ethers are locked in the contract\n\"\"\"\nfrom typing import List\n\nfrom slither.core.declarations.contract import Contract\nfrom slither.detectors.abstract_detector import (\n    AbstractDetector,\n    DetectorClassification,\n    DETECTOR_INFO,\n)\nfrom slither.slithir.operations import (\n    HighLevelCall,\n    LowLevelCall,\n    Send,\n    Transfer,\n    NewContract,\n    LibraryCall,\n    InternalCall,\n)\nfrom slither.utils.output import Output\n\n\nclass LockedEther(AbstractDetector):  # pylint: disable=too-many-nested-blocks\n\n    ARGUMENT = \"locked-ether\"\n    HELP = \"Contracts that lock ether\"\n    IMPACT = DetectorClassification.MEDIUM\n    CONFIDENCE = DetectorClassification.HIGH\n\n    WIKI = \"https://github.com/crytic/slither/wiki/Detector-Documentation#contracts-that-lock-ether\"\n\n    WIKI_TITLE = \"Contracts that lock Ether\"\n    WIKI_DESCRIPTION = \"Contract with a `payable` function, but without a withdrawal capacity.\"\n\n    # region wiki_exploit_scenario\n    WIKI_EXPLOIT_SCENARIO = \"\"\"\n```solidity\npragma solidity 0.4.24;\ncontract Locked{\n    function receive() payable public{\n    }\n}\n```\nEvery Ether sent to `Locked` will be lost.\"\"\"\n    # endregion wiki_exploit_scenario\n\n    WIKI_RECOMMENDATION = \"Remove the payable attribute or add a withdraw function.\"\n\n    @staticmethod\n    def do_no_send_ether(contract: Contract) -> bool:\n        functions = contract.all_functions_called\n        to_explore = functions\n        explored = []\n        while to_explore:  # pylint: disable=too-many-nested-blocks\n            functions = to_explore\n            explored += to_explore\n            to_explore = []\n            for function in functions:\n                calls = [c.name for c in function.internal_calls]\n                if \"suicide(address)\" in calls or \"selfdestruct(address)\" in calls:\n                    return False\n                for node in function.nodes:\n                    for ir in node.irs:\n                        if isinstance(\n                            ir,\n                            (Send, Transfer, HighLevelCall, LowLevelCall, NewContract),\n                        ):\n                            if ir.call_value and ir.call_value != 0:\n                                return False\n                        if isinstance(ir, (LowLevelCall)):\n                            if ir.function_name in [\"delegatecall\", \"callcode\"]:\n                                return False\n                        # If a new internal call or librarycall\n                        # Add it to the list to explore\n                        # InternalCall if to follow internal call in libraries\n                        if isinstance(ir, (InternalCall, LibraryCall)):\n                            if not ir.function in explored:\n                                to_explore.append(ir.function)\n\n        return True\n\n    def _detect(self) -> List[Output]:\n        results = []\n\n        for contract in self.compilation_unit.contracts_derived:\n            if contract.is_signature_only():\n                continue\n            funcs_payable = [function for function in contract.functions if function.payable]\n            if funcs_payable:\n                if self.do_no_send_ether(contract):\n                    info: DETECTOR_INFO = [\"Contract locking ether found:\\n\"]\n                    info += [\"\\tContract \", contract, \" has payable functions:\\n\"]\n                    for function in funcs_payable:\n                        info += [\"\\t - \", function, \"\\n\"]\n                    info += \"\\tBut does not have a function to withdraw the ether\\n\"\n\n                    json = self.generate_result(info)\n\n                    results.append(json)\n\n        return results\n", "path": "slither/detectors/attributes/locked_ether.py"}], "after_files": [{"content": "\"\"\"\n    Check if ethers are locked in the contract\n\"\"\"\nfrom typing import List\n\nfrom slither.core.declarations import Contract, SolidityFunction\nfrom slither.detectors.abstract_detector import (\n    AbstractDetector,\n    DetectorClassification,\n    DETECTOR_INFO,\n)\nfrom slither.slithir.operations import (\n    HighLevelCall,\n    LowLevelCall,\n    Send,\n    Transfer,\n    NewContract,\n    LibraryCall,\n    InternalCall,\n    SolidityCall,\n)\nfrom slither.slithir.variables import Constant\nfrom slither.utils.output import Output\n\n\nclass LockedEther(AbstractDetector):  # pylint: disable=too-many-nested-blocks\n\n    ARGUMENT = \"locked-ether\"\n    HELP = \"Contracts that lock ether\"\n    IMPACT = DetectorClassification.MEDIUM\n    CONFIDENCE = DetectorClassification.HIGH\n\n    WIKI = \"https://github.com/crytic/slither/wiki/Detector-Documentation#contracts-that-lock-ether\"\n\n    WIKI_TITLE = \"Contracts that lock Ether\"\n    WIKI_DESCRIPTION = \"Contract with a `payable` function, but without a withdrawal capacity.\"\n\n    # region wiki_exploit_scenario\n    WIKI_EXPLOIT_SCENARIO = \"\"\"\n```solidity\npragma solidity 0.4.24;\ncontract Locked{\n    function receive() payable public{\n    }\n}\n```\nEvery Ether sent to `Locked` will be lost.\"\"\"\n    # endregion wiki_exploit_scenario\n\n    WIKI_RECOMMENDATION = \"Remove the payable attribute or add a withdraw function.\"\n\n    @staticmethod\n    def do_no_send_ether(contract: Contract) -> bool:\n        functions = contract.all_functions_called\n        to_explore = functions\n        explored = []\n        while to_explore:  # pylint: disable=too-many-nested-blocks\n            functions = to_explore\n            explored += to_explore\n            to_explore = []\n            for function in functions:\n                calls = [c.name for c in function.internal_calls]\n                if \"suicide(address)\" in calls or \"selfdestruct(address)\" in calls:\n                    return False\n                for node in function.nodes:\n                    for ir in node.irs:\n                        if isinstance(\n                            ir,\n                            (Send, Transfer, HighLevelCall, LowLevelCall, NewContract),\n                        ):\n                            if ir.call_value and ir.call_value != 0:\n                                return False\n                        if isinstance(ir, (LowLevelCall)) and ir.function_name in [\n                            \"delegatecall\",\n                            \"callcode\",\n                        ]:\n                            return False\n                        if isinstance(ir, SolidityCall):\n                            call_can_send_ether = ir.function in [\n                                SolidityFunction(\n                                    \"delegatecall(uint256,uint256,uint256,uint256,uint256,uint256)\"\n                                ),\n                                SolidityFunction(\n                                    \"callcode(uint256,uint256,uint256,uint256,uint256,uint256,uint256)\"\n                                ),\n                                SolidityFunction(\n                                    \"call(uint256,uint256,uint256,uint256,uint256,uint256,uint256)\"\n                                ),\n                            ]\n                            nonzero_call_value = call_can_send_ether and (\n                                not isinstance(ir.arguments[2], Constant)\n                                or ir.arguments[2].value != 0\n                            )\n                            if nonzero_call_value:\n                                return False\n                        # If a new internal call or librarycall\n                        # Add it to the list to explore\n                        # InternalCall if to follow internal call in libraries\n                        if isinstance(ir, (InternalCall, LibraryCall)):\n                            if not ir.function in explored:\n                                to_explore.append(ir.function)\n\n        return True\n\n    def _detect(self) -> List[Output]:\n        results = []\n\n        for contract in self.compilation_unit.contracts_derived:\n            if contract.is_signature_only():\n                continue\n            funcs_payable = [function for function in contract.functions if function.payable]\n            if funcs_payable:\n                if self.do_no_send_ether(contract):\n                    info: DETECTOR_INFO = [\"Contract locking ether found:\\n\"]\n                    info += [\"\\tContract \", contract, \" has payable functions:\\n\"]\n                    for function in funcs_payable:\n                        info += [\"\\t - \", function, \"\\n\"]\n                    info += \"\\tBut does not have a function to withdraw the ether\\n\"\n\n                    json = self.generate_result(info)\n\n                    results.append(json)\n\n        return results\n", "path": "slither/detectors/attributes/locked_ether.py"}]}