We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Runtime error when making an external call to the same contract
This code makes it an error to make an external call to the same contract:

https://github.com/ethereum/vyper/blob/c296b2d7532d913103aad494b749f8179a3acddc/vyper/parser/external_call.py#L75

This is a surprising limitation. It doesn't seem to have a clear benefit, and it could be problematic. As an example, multisig wallets often use self-calls to perform administrative functions. This way the wallet owners have to agree to make a change like lowering the required threshold of signatures. In Vyper, this would produce a runtime error.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `vyper/parser/external_call.py`
Content:
```
1 from vyper import ast as vy_ast
2 from vyper.exceptions import (
3     StateAccessViolation,
4     StructureException,
5     TypeCheckFailure,
6 )
7 from vyper.parser.lll_node import LLLnode
8 from vyper.parser.parser_utils import getpos, pack_arguments, unwrap_location
9 from vyper.types import (
10     BaseType,
11     ByteArrayLike,
12     ListType,
13     TupleLike,
14     get_size_of_type,
15 )
16 
17 
18 def external_call(node, context, interface_name, contract_address, pos, value=None, gas=None):
19     from vyper.parser.expr import Expr
20 
21     if value is None:
22         value = 0
23     if gas is None:
24         gas = "gas"
25     if contract_address.value == "address":
26         raise StructureException("External calls to self are not permitted.", node)
27     method_name = node.func.attr
28     sig = context.sigs[interface_name][method_name]
29     inargs, inargsize, _ = pack_arguments(
30         sig, [Expr(arg, context).lll_node for arg in node.args], context, node.func,
31     )
32     output_placeholder, output_size, returner = get_external_call_output(sig, context)
33     sub = [
34         "seq",
35         ["assert", ["extcodesize", contract_address]],
36         ["assert", ["ne", "address", contract_address]],
37     ]
38     if context.is_constant() and not sig.const:
39         # TODO this can probably go
40         raise StateAccessViolation(
41             f"May not call state modifying function '{method_name}' "
42             f"within {context.pp_constancy()}.",
43             node,
44         )
45 
46     if context.is_constant() or sig.const:
47         sub.append(
48             [
49                 "assert",
50                 [
51                     "staticcall",
52                     gas,
53                     contract_address,
54                     inargs,
55                     inargsize,
56                     output_placeholder,
57                     output_size,
58                 ],
59             ]
60         )
61     else:
62         sub.append(
63             [
64                 "assert",
65                 [
66                     "call",
67                     gas,
68                     contract_address,
69                     value,
70                     inargs,
71                     inargsize,
72                     output_placeholder,
73                     output_size,
74                 ],
75             ]
76         )
77     sub.extend(returner)
78     o = LLLnode.from_list(sub, typ=sig.output_type, location="memory", pos=getpos(node))
79     return o
80 
81 
82 def get_external_call_output(sig, context):
83     if not sig.output_type:
84         return 0, 0, []
85     output_placeholder = context.new_placeholder(typ=sig.output_type)
86     output_size = get_size_of_type(sig.output_type) * 32
87     if isinstance(sig.output_type, BaseType):
88         returner = [0, output_placeholder]
89     elif isinstance(sig.output_type, ByteArrayLike):
90         returner = [0, output_placeholder + 32]
91     elif isinstance(sig.output_type, TupleLike):
92         returner = [0, output_placeholder]
93     elif isinstance(sig.output_type, ListType):
94         returner = [0, output_placeholder]
95     else:
96         raise TypeCheckFailure(f"Invalid output type: {sig.output_type}")
97     return output_placeholder, output_size, returner
98 
99 
100 def get_external_interface_keywords(stmt_expr, context):
101     from vyper.parser.expr import Expr
102 
103     value, gas = None, None
104     for kw in stmt_expr.keywords:
105         if kw.arg == "gas":
106             gas = Expr.parse_value_expr(kw.value, context)
107         elif kw.arg == "value":
108             value = Expr.parse_value_expr(kw.value, context)
109         else:
110             raise TypeCheckFailure("Unexpected keyword argument")
111     return value, gas
112 
113 
114 def make_external_call(stmt_expr, context):
115     from vyper.parser.expr import Expr
116 
117     value, gas = get_external_interface_keywords(stmt_expr, context)
118 
119     if isinstance(stmt_expr.func, vy_ast.Attribute) and isinstance(
120         stmt_expr.func.value, vy_ast.Call
121     ):
122         contract_name = stmt_expr.func.value.func.id
123         contract_address = Expr.parse_value_expr(stmt_expr.func.value.args[0], context)
124 
125         return external_call(
126             stmt_expr,
127             context,
128             contract_name,
129             contract_address,
130             pos=getpos(stmt_expr),
131             value=value,
132             gas=gas,
133         )
134 
135     elif (
136         isinstance(stmt_expr.func.value, vy_ast.Attribute)
137         and stmt_expr.func.value.attr in context.sigs
138     ):  # noqa: E501
139         contract_name = stmt_expr.func.value.attr
140         var = context.globals[stmt_expr.func.value.attr]
141         contract_address = unwrap_location(
142             LLLnode.from_list(
143                 var.pos,
144                 typ=var.typ,
145                 location="storage",
146                 pos=getpos(stmt_expr),
147                 annotation="self." + stmt_expr.func.value.attr,
148             )
149         )
150 
151         return external_call(
152             stmt_expr,
153             context,
154             contract_name,
155             contract_address,
156             pos=getpos(stmt_expr),
157             value=value,
158             gas=gas,
159         )
160 
161     elif (
162         isinstance(stmt_expr.func.value, vy_ast.Attribute)
163         and stmt_expr.func.value.attr in context.globals
164         and hasattr(context.globals[stmt_expr.func.value.attr].typ, "name")
165     ):
166 
167         contract_name = context.globals[stmt_expr.func.value.attr].typ.name
168         var = context.globals[stmt_expr.func.value.attr]
169         contract_address = unwrap_location(
170             LLLnode.from_list(
171                 var.pos,
172                 typ=var.typ,
173                 location="storage",
174                 pos=getpos(stmt_expr),
175                 annotation="self." + stmt_expr.func.value.attr,
176             )
177         )
178 
179         return external_call(
180             stmt_expr,
181             context,
182             contract_name,
183             contract_address,
184             pos=getpos(stmt_expr),
185             value=value,
186             gas=gas,
187         )
188 
189     else:
190         raise StructureException("Unsupported operator.", stmt_expr)
191
```
--- 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()

```

diff --git a/vyper/parser/external_call.py b/vyper/parser/external_call.py
--- a/vyper/parser/external_call.py
+++ b/vyper/parser/external_call.py
@@ -22,8 +22,7 @@
         value = 0
     if gas is None:
         gas = "gas"
-    if contract_address.value == "address":
-        raise StructureException("External calls to self are not permitted.", node)
+
     method_name = node.func.attr
     sig = context.sigs[interface_name][method_name]
     inargs, inargsize, _ = pack_arguments(
@@ -33,7 +32,6 @@
     sub = [
         "seq",
         ["assert", ["extcodesize", contract_address]],
-        ["assert", ["ne", "address", contract_address]],
     ]
     if context.is_constant() and not sig.const:
         # TODO this can probably go

{"golden_diff": "diff --git a/vyper/parser/external_call.py b/vyper/parser/external_call.py\n--- a/vyper/parser/external_call.py\n+++ b/vyper/parser/external_call.py\n@@ -22,8 +22,7 @@\n         value = 0\n     if gas is None:\n         gas = \"gas\"\n-    if contract_address.value == \"address\":\n-        raise StructureException(\"External calls to self are not permitted.\", node)\n+\n     method_name = node.func.attr\n     sig = context.sigs[interface_name][method_name]\n     inargs, inargsize, _ = pack_arguments(\n@@ -33,7 +32,6 @@\n     sub = [\n         \"seq\",\n         [\"assert\", [\"extcodesize\", contract_address]],\n-        [\"assert\", [\"ne\", \"address\", contract_address]],\n     ]\n     if context.is_constant() and not sig.const:\n         # TODO this can probably go\n", "issue": "Runtime error when making an external call to the same contract\nThis code makes it an error to make an external call to the same contract:\r\n\r\nhttps://github.com/ethereum/vyper/blob/c296b2d7532d913103aad494b749f8179a3acddc/vyper/parser/external_call.py#L75\r\n\r\nThis is a surprising limitation. It doesn't seem to have a clear benefit, and it could be problematic. As an example, multisig wallets often use self-calls to perform administrative functions. This way the wallet owners have to agree to make a change like lowering the required threshold of signatures. In Vyper, this would produce a runtime error.\n", "before_files": [{"content": "from vyper import ast as vy_ast\nfrom vyper.exceptions import (\n    StateAccessViolation,\n    StructureException,\n    TypeCheckFailure,\n)\nfrom vyper.parser.lll_node import LLLnode\nfrom vyper.parser.parser_utils import getpos, pack_arguments, unwrap_location\nfrom vyper.types import (\n    BaseType,\n    ByteArrayLike,\n    ListType,\n    TupleLike,\n    get_size_of_type,\n)\n\n\ndef external_call(node, context, interface_name, contract_address, pos, value=None, gas=None):\n    from vyper.parser.expr import Expr\n\n    if value is None:\n        value = 0\n    if gas is None:\n        gas = \"gas\"\n    if contract_address.value == \"address\":\n        raise StructureException(\"External calls to self are not permitted.\", node)\n    method_name = node.func.attr\n    sig = context.sigs[interface_name][method_name]\n    inargs, inargsize, _ = pack_arguments(\n        sig, [Expr(arg, context).lll_node for arg in node.args], context, node.func,\n    )\n    output_placeholder, output_size, returner = get_external_call_output(sig, context)\n    sub = [\n        \"seq\",\n        [\"assert\", [\"extcodesize\", contract_address]],\n        [\"assert\", [\"ne\", \"address\", contract_address]],\n    ]\n    if context.is_constant() and not sig.const:\n        # TODO this can probably go\n        raise StateAccessViolation(\n            f\"May not call state modifying function '{method_name}' \"\n            f\"within {context.pp_constancy()}.\",\n            node,\n        )\n\n    if context.is_constant() or sig.const:\n        sub.append(\n            [\n                \"assert\",\n                [\n                    \"staticcall\",\n                    gas,\n                    contract_address,\n                    inargs,\n                    inargsize,\n                    output_placeholder,\n                    output_size,\n                ],\n            ]\n        )\n    else:\n        sub.append(\n            [\n                \"assert\",\n                [\n                    \"call\",\n                    gas,\n                    contract_address,\n                    value,\n                    inargs,\n                    inargsize,\n                    output_placeholder,\n                    output_size,\n                ],\n            ]\n        )\n    sub.extend(returner)\n    o = LLLnode.from_list(sub, typ=sig.output_type, location=\"memory\", pos=getpos(node))\n    return o\n\n\ndef get_external_call_output(sig, context):\n    if not sig.output_type:\n        return 0, 0, []\n    output_placeholder = context.new_placeholder(typ=sig.output_type)\n    output_size = get_size_of_type(sig.output_type) * 32\n    if isinstance(sig.output_type, BaseType):\n        returner = [0, output_placeholder]\n    elif isinstance(sig.output_type, ByteArrayLike):\n        returner = [0, output_placeholder + 32]\n    elif isinstance(sig.output_type, TupleLike):\n        returner = [0, output_placeholder]\n    elif isinstance(sig.output_type, ListType):\n        returner = [0, output_placeholder]\n    else:\n        raise TypeCheckFailure(f\"Invalid output type: {sig.output_type}\")\n    return output_placeholder, output_size, returner\n\n\ndef get_external_interface_keywords(stmt_expr, context):\n    from vyper.parser.expr import Expr\n\n    value, gas = None, None\n    for kw in stmt_expr.keywords:\n        if kw.arg == \"gas\":\n            gas = Expr.parse_value_expr(kw.value, context)\n        elif kw.arg == \"value\":\n            value = Expr.parse_value_expr(kw.value, context)\n        else:\n            raise TypeCheckFailure(\"Unexpected keyword argument\")\n    return value, gas\n\n\ndef make_external_call(stmt_expr, context):\n    from vyper.parser.expr import Expr\n\n    value, gas = get_external_interface_keywords(stmt_expr, context)\n\n    if isinstance(stmt_expr.func, vy_ast.Attribute) and isinstance(\n        stmt_expr.func.value, vy_ast.Call\n    ):\n        contract_name = stmt_expr.func.value.func.id\n        contract_address = Expr.parse_value_expr(stmt_expr.func.value.args[0], context)\n\n        return external_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    elif (\n        isinstance(stmt_expr.func.value, vy_ast.Attribute)\n        and stmt_expr.func.value.attr in context.sigs\n    ):  # noqa: E501\n        contract_name = stmt_expr.func.value.attr\n        var = context.globals[stmt_expr.func.value.attr]\n        contract_address = unwrap_location(\n            LLLnode.from_list(\n                var.pos,\n                typ=var.typ,\n                location=\"storage\",\n                pos=getpos(stmt_expr),\n                annotation=\"self.\" + stmt_expr.func.value.attr,\n            )\n        )\n\n        return external_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    elif (\n        isinstance(stmt_expr.func.value, vy_ast.Attribute)\n        and stmt_expr.func.value.attr in context.globals\n        and hasattr(context.globals[stmt_expr.func.value.attr].typ, \"name\")\n    ):\n\n        contract_name = context.globals[stmt_expr.func.value.attr].typ.name\n        var = context.globals[stmt_expr.func.value.attr]\n        contract_address = unwrap_location(\n            LLLnode.from_list(\n                var.pos,\n                typ=var.typ,\n                location=\"storage\",\n                pos=getpos(stmt_expr),\n                annotation=\"self.\" + stmt_expr.func.value.attr,\n            )\n        )\n\n        return external_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    else:\n        raise StructureException(\"Unsupported operator.\", stmt_expr)\n", "path": "vyper/parser/external_call.py"}], "after_files": [{"content": "from vyper import ast as vy_ast\nfrom vyper.exceptions import (\n    StateAccessViolation,\n    StructureException,\n    TypeCheckFailure,\n)\nfrom vyper.parser.lll_node import LLLnode\nfrom vyper.parser.parser_utils import getpos, pack_arguments, unwrap_location\nfrom vyper.types import (\n    BaseType,\n    ByteArrayLike,\n    ListType,\n    TupleLike,\n    get_size_of_type,\n)\n\n\ndef external_call(node, context, interface_name, contract_address, pos, value=None, gas=None):\n    from vyper.parser.expr import Expr\n\n    if value is None:\n        value = 0\n    if gas is None:\n        gas = \"gas\"\n\n    method_name = node.func.attr\n    sig = context.sigs[interface_name][method_name]\n    inargs, inargsize, _ = pack_arguments(\n        sig, [Expr(arg, context).lll_node for arg in node.args], context, node.func,\n    )\n    output_placeholder, output_size, returner = get_external_call_output(sig, context)\n    sub = [\n        \"seq\",\n        [\"assert\", [\"extcodesize\", contract_address]],\n    ]\n    if context.is_constant() and not sig.const:\n        # TODO this can probably go\n        raise StateAccessViolation(\n            f\"May not call state modifying function '{method_name}' \"\n            f\"within {context.pp_constancy()}.\",\n            node,\n        )\n\n    if context.is_constant() or sig.const:\n        sub.append(\n            [\n                \"assert\",\n                [\n                    \"staticcall\",\n                    gas,\n                    contract_address,\n                    inargs,\n                    inargsize,\n                    output_placeholder,\n                    output_size,\n                ],\n            ]\n        )\n    else:\n        sub.append(\n            [\n                \"assert\",\n                [\n                    \"call\",\n                    gas,\n                    contract_address,\n                    value,\n                    inargs,\n                    inargsize,\n                    output_placeholder,\n                    output_size,\n                ],\n            ]\n        )\n    sub.extend(returner)\n    o = LLLnode.from_list(sub, typ=sig.output_type, location=\"memory\", pos=getpos(node))\n    return o\n\n\ndef get_external_call_output(sig, context):\n    if not sig.output_type:\n        return 0, 0, []\n    output_placeholder = context.new_placeholder(typ=sig.output_type)\n    output_size = get_size_of_type(sig.output_type) * 32\n    if isinstance(sig.output_type, BaseType):\n        returner = [0, output_placeholder]\n    elif isinstance(sig.output_type, ByteArrayLike):\n        returner = [0, output_placeholder + 32]\n    elif isinstance(sig.output_type, TupleLike):\n        returner = [0, output_placeholder]\n    elif isinstance(sig.output_type, ListType):\n        returner = [0, output_placeholder]\n    else:\n        raise TypeCheckFailure(f\"Invalid output type: {sig.output_type}\")\n    return output_placeholder, output_size, returner\n\n\ndef get_external_interface_keywords(stmt_expr, context):\n    from vyper.parser.expr import Expr\n\n    value, gas = None, None\n    for kw in stmt_expr.keywords:\n        if kw.arg == \"gas\":\n            gas = Expr.parse_value_expr(kw.value, context)\n        elif kw.arg == \"value\":\n            value = Expr.parse_value_expr(kw.value, context)\n        else:\n            raise TypeCheckFailure(\"Unexpected keyword argument\")\n    return value, gas\n\n\ndef make_external_call(stmt_expr, context):\n    from vyper.parser.expr import Expr\n\n    value, gas = get_external_interface_keywords(stmt_expr, context)\n\n    if isinstance(stmt_expr.func, vy_ast.Attribute) and isinstance(\n        stmt_expr.func.value, vy_ast.Call\n    ):\n        contract_name = stmt_expr.func.value.func.id\n        contract_address = Expr.parse_value_expr(stmt_expr.func.value.args[0], context)\n\n        return external_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    elif (\n        isinstance(stmt_expr.func.value, vy_ast.Attribute)\n        and stmt_expr.func.value.attr in context.sigs\n    ):  # noqa: E501\n        contract_name = stmt_expr.func.value.attr\n        var = context.globals[stmt_expr.func.value.attr]\n        contract_address = unwrap_location(\n            LLLnode.from_list(\n                var.pos,\n                typ=var.typ,\n                location=\"storage\",\n                pos=getpos(stmt_expr),\n                annotation=\"self.\" + stmt_expr.func.value.attr,\n            )\n        )\n\n        return external_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    elif (\n        isinstance(stmt_expr.func.value, vy_ast.Attribute)\n        and stmt_expr.func.value.attr in context.globals\n        and hasattr(context.globals[stmt_expr.func.value.attr].typ, \"name\")\n    ):\n\n        contract_name = context.globals[stmt_expr.func.value.attr].typ.name\n        var = context.globals[stmt_expr.func.value.attr]\n        contract_address = unwrap_location(\n            LLLnode.from_list(\n                var.pos,\n                typ=var.typ,\n                location=\"storage\",\n                pos=getpos(stmt_expr),\n                annotation=\"self.\" + stmt_expr.func.value.attr,\n            )\n        )\n\n        return external_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    else:\n        raise StructureException(\"Unsupported operator.\", stmt_expr)\n", "path": "vyper/parser/external_call.py"}]}