We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
vyper.exceptions.TypeCheckFailure: pack_arguments did not return a value
### Version Information

* vyper Version (output of `vyper --version`): 0.2.16
* OS: osx
* Python Version (output of `python --version`): python3

### I tried to compile my codes using "vyper file_name.vy" and this is the error I get

Please include information like:

*Error compiling: bounty.v
![Screenshot 2021-11-03 at 9 42 39 PM](https://user-images.githubusercontent.com/54287741/140189733-b037b084-b805-4f25-aa85-eee83b0b1727.png)
y
vyper.exceptions.TypeCheckFailure: pack_arguments did not return a value

This is an unhandled internal compiler error. Please create an issue on Github to notify the developers.
* vyper
* the code that caused the failure (see [this link](https://help.github.com/articles/basic-writing-and-formatting-syntax/) for help with formatting code)
* please try running your example with the --debug flag turned on


### How can it be fixed?

Fill this in if you know how to fix it.
![Screenshot 2021-11-03 at 9 42 39 PM](https://user-images.githubusercontent.com/54287741/140189784-eb38f9fd-2994-4537-8a4a-8a6cf5f96d30.png)



--- 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/old_codegen/external_call.py`
Content:
```
1 import vyper.utils as util
2 from vyper import ast as vy_ast
3 from vyper.exceptions import StateAccessViolation, StructureException, TypeCheckFailure
4 from vyper.old_codegen.abi import abi_encode, abi_type_of
5 from vyper.old_codegen.lll_node import Encoding, LLLnode
6 from vyper.old_codegen.parser_utils import (
7     calculate_type_for_external_return,
8     get_element_ptr,
9     getpos,
10     unwrap_location,
11 )
12 from vyper.old_codegen.types import TupleType, canonicalize_type, get_type_for_exact_size
13 from vyper.old_codegen.types.check import check_assign
14 
15 
16 def _pack_arguments(contract_sig, args, context, pos):
17     # abi encoding just treats all args as a big tuple
18     args_tuple_t = TupleType([x.typ for x in args])
19     args_as_tuple = LLLnode.from_list(["multi"] + [x for x in args], typ=args_tuple_t)
20     args_abi_t = abi_type_of(args_tuple_t)
21 
22     # sanity typecheck - make sure the arguments can be assigned
23     dst_tuple_t = TupleType([arg.typ for arg in contract_sig.args][: len(args)])
24     _tmp = LLLnode("fake node", location="memory", typ=dst_tuple_t)
25     check_assign(_tmp, args_as_tuple, pos)
26 
27     if contract_sig.return_type is not None:
28         return_abi_t = abi_type_of(calculate_type_for_external_return(contract_sig.return_type))
29 
30         # we use the same buffer for args and returndata,
31         # so allocate enough space here for the returndata too.
32         buflen = max(args_abi_t.size_bound(), return_abi_t.size_bound())
33     else:
34         buflen = args_abi_t.size_bound()
35 
36     buflen += 32  # padding for the method id
37 
38     buf_t = get_type_for_exact_size(buflen)
39     buf = context.new_internal_variable(buf_t)
40 
41     args_ofst = buf + 28
42     args_len = args_abi_t.size_bound() + 4
43 
44     abi_signature = contract_sig.name + canonicalize_type(dst_tuple_t)
45 
46     # layout:
47     # 32 bytes                 | args
48     # 0x..00<method_id_4bytes> | args
49     # the reason for the left padding is just so the alignment is easier.
50     # if we were only targeting constantinople, we could align
51     # to buf (and also keep code size small) by using
52     # (mstore buf (shl signature.method_id 224))
53     mstore_method_id = [["mstore", buf, util.abi_method_id(abi_signature)]]
54 
55     if len(args) == 0:
56         encode_args = ["pass"]
57     else:
58         encode_args = abi_encode(buf + 32, args_as_tuple, pos)
59 
60     return buf, mstore_method_id + [encode_args], args_ofst, args_len
61 
62 
63 def _returndata_encoding(contract_sig):
64     if contract_sig.is_from_json:
65         return Encoding.JSON_ABI
66     return Encoding.ABI
67 
68 
69 def _unpack_returndata(buf, contract_sig, context, pos):
70     return_t = contract_sig.return_type
71     if return_t is None:
72         return ["pass"], 0, 0
73 
74     return_t = calculate_type_for_external_return(return_t)
75     # if the abi signature has a different type than
76     # the vyper type, we need to wrap and unwrap the type
77     # so that the ABI decoding works correctly
78     should_unwrap_abi_tuple = return_t != contract_sig.return_type
79 
80     abi_return_t = abi_type_of(return_t)
81 
82     min_return_size = abi_return_t.min_size()
83     max_return_size = abi_return_t.size_bound()
84     assert 0 < min_return_size <= max_return_size
85 
86     ret_ofst = buf
87     ret_len = max_return_size
88 
89     # revert when returndatasize is not in bounds
90     ret = []
91     # runtime: min_return_size <= returndatasize
92     # TODO move the -1 optimization to LLL optimizer
93     ret += [["assert", ["gt", "returndatasize", min_return_size - 1]]]
94 
95     # add as the last LLLnode a pointer to the return data structure
96 
97     # the return type has been wrapped by the calling contract;
98     # unwrap it so downstream code isn't confused.
99     # basically this expands to buf+32 if the return type has been wrapped
100     # in a tuple AND its ABI type is dynamic.
101     # in most cases, this simply will evaluate to ret.
102     # in the special case where the return type has been wrapped
103     # in a tuple AND its ABI type is dynamic, it expands to buf+32.
104     buf = LLLnode(buf, typ=return_t, encoding=_returndata_encoding(contract_sig), location="memory")
105 
106     if should_unwrap_abi_tuple:
107         buf = get_element_ptr(buf, 0, pos=None, array_bounds_check=False)
108 
109     ret += [buf]
110 
111     return ret, ret_ofst, ret_len
112 
113 
114 def _external_call_helper(
115     contract_address, contract_sig, args_lll, context, pos=None, value=None, gas=None
116 ):
117 
118     if value is None:
119         value = 0
120     if gas is None:
121         gas = "gas"
122 
123     # sanity check
124     assert len(contract_sig.args) == len(args_lll)
125 
126     if context.is_constant() and contract_sig.mutability not in ("view", "pure"):
127         # TODO is this already done in type checker?
128         raise StateAccessViolation(
129             f"May not call state modifying function '{contract_sig.name}' "
130             f"within {context.pp_constancy()}.",
131             pos,
132         )
133 
134     sub = ["seq"]
135 
136     buf, arg_packer, args_ofst, args_len = _pack_arguments(contract_sig, args_lll, context, pos)
137 
138     ret_unpacker, ret_ofst, ret_len = _unpack_returndata(buf, contract_sig, context, pos)
139 
140     sub += arg_packer
141 
142     if contract_sig.return_type is None:
143         # if we do not expect return data, check that a contract exists at the
144         # target address. we must perform this check BEFORE the call because
145         # the contract might selfdestruct. on the other hand we can omit this
146         # when we _do_ expect return data because we later check
147         # `returndatasize` (that check works even if the contract
148         # selfdestructs).
149         sub.append(["assert", ["extcodesize", contract_address]])
150 
151     if context.is_constant() or contract_sig.mutability in ("view", "pure"):
152         call_op = ["staticcall", gas, contract_address, args_ofst, args_len, ret_ofst, ret_len]
153     else:
154         call_op = ["call", gas, contract_address, value, args_ofst, args_len, ret_ofst, ret_len]
155 
156     sub.append(["assert", call_op])
157 
158     if contract_sig.return_type is not None:
159         sub += ret_unpacker
160 
161     ret = LLLnode.from_list(
162         # set the encoding to ABI here, downstream code will decode and add clampers.
163         sub,
164         typ=contract_sig.return_type,
165         location="memory",
166         encoding=_returndata_encoding(contract_sig),
167         pos=pos,
168     )
169 
170     return ret
171 
172 
173 # TODO push me up to expr.py
174 def get_gas_and_value(stmt_expr, context):
175     from vyper.old_codegen.expr import Expr  # TODO rethink this circular import
176 
177     value, gas = None, None
178     for kw in stmt_expr.keywords:
179         if kw.arg == "gas":
180             gas = Expr.parse_value_expr(kw.value, context)
181         elif kw.arg == "value":
182             value = Expr.parse_value_expr(kw.value, context)
183         else:
184             raise TypeCheckFailure("Unexpected keyword argument")
185     return value, gas
186 
187 
188 def lll_for_external_call(stmt_expr, context):
189     from vyper.old_codegen.expr import Expr  # TODO rethink this circular import
190 
191     pos = getpos(stmt_expr)
192     value, gas = get_gas_and_value(stmt_expr, context)
193     args_lll = [Expr(x, context).lll_node for x in stmt_expr.args]
194 
195     if isinstance(stmt_expr.func, vy_ast.Attribute) and isinstance(
196         stmt_expr.func.value, vy_ast.Call
197     ):
198         # e.g. `Foo(address).bar()`
199 
200         # sanity check
201         assert len(stmt_expr.func.value.args) == 1
202         contract_name = stmt_expr.func.value.func.id
203         contract_address = Expr.parse_value_expr(stmt_expr.func.value.args[0], context)
204 
205     elif (
206         isinstance(stmt_expr.func.value, vy_ast.Attribute)
207         and stmt_expr.func.value.attr in context.globals
208         # TODO check for self?
209         and hasattr(context.globals[stmt_expr.func.value.attr].typ, "name")
210     ):
211         # e.g. `self.foo.bar()`
212 
213         # sanity check
214         assert stmt_expr.func.value.value.id == "self", stmt_expr
215 
216         contract_name = context.globals[stmt_expr.func.value.attr].typ.name
217         type_ = stmt_expr.func.value._metadata["type"]
218         var = context.globals[stmt_expr.func.value.attr]
219         contract_address = unwrap_location(
220             LLLnode.from_list(
221                 type_.position.position,
222                 typ=var.typ,
223                 location="storage",
224                 pos=pos,
225                 annotation="self." + stmt_expr.func.value.attr,
226             )
227         )
228     else:
229         # TODO catch this during type checking
230         raise StructureException("Unsupported operator.", stmt_expr)
231 
232     method_name = stmt_expr.func.attr
233     contract_sig = context.sigs[contract_name][method_name]
234 
235     ret = _external_call_helper(
236         contract_address,
237         contract_sig,
238         args_lll,
239         context,
240         pos,
241         value=value,
242         gas=gas,
243     )
244     ret.annotation = stmt_expr.get("node_source_code")
245 
246     return ret
247
```
--- 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/old_codegen/external_call.py b/vyper/old_codegen/external_call.py
--- a/vyper/old_codegen/external_call.py
+++ b/vyper/old_codegen/external_call.py
@@ -121,7 +121,7 @@
         gas = "gas"
 
     # sanity check
-    assert len(contract_sig.args) == len(args_lll)
+    assert len(contract_sig.base_args) <= len(args_lll) <= len(contract_sig.args)
 
     if context.is_constant() and contract_sig.mutability not in ("view", "pure"):
         # TODO is this already done in type checker?

{"golden_diff": "diff --git a/vyper/old_codegen/external_call.py b/vyper/old_codegen/external_call.py\n--- a/vyper/old_codegen/external_call.py\n+++ b/vyper/old_codegen/external_call.py\n@@ -121,7 +121,7 @@\n         gas = \"gas\"\n \n     # sanity check\n-    assert len(contract_sig.args) == len(args_lll)\n+    assert len(contract_sig.base_args) <= len(args_lll) <= len(contract_sig.args)\n \n     if context.is_constant() and contract_sig.mutability not in (\"view\", \"pure\"):\n         # TODO is this already done in type checker?\n", "issue": "vyper.exceptions.TypeCheckFailure: pack_arguments did not return a value\n### Version Information\r\n\r\n* vyper Version (output of `vyper --version`): 0.2.16\r\n* OS: osx\r\n* Python Version (output of `python --version`): python3\r\n\r\n### I tried to compile my codes using \"vyper file_name.vy\" and this is the error I get\r\n\r\nPlease include information like:\r\n\r\n*Error compiling: bounty.v\r\n![Screenshot 2021-11-03 at 9 42 39 PM](https://user-images.githubusercontent.com/54287741/140189733-b037b084-b805-4f25-aa85-eee83b0b1727.png)\r\ny\r\nvyper.exceptions.TypeCheckFailure: pack_arguments did not return a value\r\n\r\nThis is an unhandled internal compiler error. Please create an issue on Github to notify the developers.\r\n* vyper\r\n* the code that caused the failure (see [this link](https://help.github.com/articles/basic-writing-and-formatting-syntax/) for help with formatting code)\r\n* please try running your example with the --debug flag turned on\r\n\r\n\r\n### How can it be fixed?\r\n\r\nFill this in if you know how to fix it.\r\n![Screenshot 2021-11-03 at 9 42 39 PM](https://user-images.githubusercontent.com/54287741/140189784-eb38f9fd-2994-4537-8a4a-8a6cf5f96d30.png)\r\n\r\n\n", "before_files": [{"content": "import vyper.utils as util\nfrom vyper import ast as vy_ast\nfrom vyper.exceptions import StateAccessViolation, StructureException, TypeCheckFailure\nfrom vyper.old_codegen.abi import abi_encode, abi_type_of\nfrom vyper.old_codegen.lll_node import Encoding, LLLnode\nfrom vyper.old_codegen.parser_utils import (\n    calculate_type_for_external_return,\n    get_element_ptr,\n    getpos,\n    unwrap_location,\n)\nfrom vyper.old_codegen.types import TupleType, canonicalize_type, get_type_for_exact_size\nfrom vyper.old_codegen.types.check import check_assign\n\n\ndef _pack_arguments(contract_sig, args, context, pos):\n    # abi encoding just treats all args as a big tuple\n    args_tuple_t = TupleType([x.typ for x in args])\n    args_as_tuple = LLLnode.from_list([\"multi\"] + [x for x in args], typ=args_tuple_t)\n    args_abi_t = abi_type_of(args_tuple_t)\n\n    # sanity typecheck - make sure the arguments can be assigned\n    dst_tuple_t = TupleType([arg.typ for arg in contract_sig.args][: len(args)])\n    _tmp = LLLnode(\"fake node\", location=\"memory\", typ=dst_tuple_t)\n    check_assign(_tmp, args_as_tuple, pos)\n\n    if contract_sig.return_type is not None:\n        return_abi_t = abi_type_of(calculate_type_for_external_return(contract_sig.return_type))\n\n        # we use the same buffer for args and returndata,\n        # so allocate enough space here for the returndata too.\n        buflen = max(args_abi_t.size_bound(), return_abi_t.size_bound())\n    else:\n        buflen = args_abi_t.size_bound()\n\n    buflen += 32  # padding for the method id\n\n    buf_t = get_type_for_exact_size(buflen)\n    buf = context.new_internal_variable(buf_t)\n\n    args_ofst = buf + 28\n    args_len = args_abi_t.size_bound() + 4\n\n    abi_signature = contract_sig.name + canonicalize_type(dst_tuple_t)\n\n    # layout:\n    # 32 bytes                 | args\n    # 0x..00<method_id_4bytes> | args\n    # the reason for the left padding is just so the alignment is easier.\n    # if we were only targeting constantinople, we could align\n    # to buf (and also keep code size small) by using\n    # (mstore buf (shl signature.method_id 224))\n    mstore_method_id = [[\"mstore\", buf, util.abi_method_id(abi_signature)]]\n\n    if len(args) == 0:\n        encode_args = [\"pass\"]\n    else:\n        encode_args = abi_encode(buf + 32, args_as_tuple, pos)\n\n    return buf, mstore_method_id + [encode_args], args_ofst, args_len\n\n\ndef _returndata_encoding(contract_sig):\n    if contract_sig.is_from_json:\n        return Encoding.JSON_ABI\n    return Encoding.ABI\n\n\ndef _unpack_returndata(buf, contract_sig, context, pos):\n    return_t = contract_sig.return_type\n    if return_t is None:\n        return [\"pass\"], 0, 0\n\n    return_t = calculate_type_for_external_return(return_t)\n    # if the abi signature has a different type than\n    # the vyper type, we need to wrap and unwrap the type\n    # so that the ABI decoding works correctly\n    should_unwrap_abi_tuple = return_t != contract_sig.return_type\n\n    abi_return_t = abi_type_of(return_t)\n\n    min_return_size = abi_return_t.min_size()\n    max_return_size = abi_return_t.size_bound()\n    assert 0 < min_return_size <= max_return_size\n\n    ret_ofst = buf\n    ret_len = max_return_size\n\n    # revert when returndatasize is not in bounds\n    ret = []\n    # runtime: min_return_size <= returndatasize\n    # TODO move the -1 optimization to LLL optimizer\n    ret += [[\"assert\", [\"gt\", \"returndatasize\", min_return_size - 1]]]\n\n    # add as the last LLLnode a pointer to the return data structure\n\n    # the return type has been wrapped by the calling contract;\n    # unwrap it so downstream code isn't confused.\n    # basically this expands to buf+32 if the return type has been wrapped\n    # in a tuple AND its ABI type is dynamic.\n    # in most cases, this simply will evaluate to ret.\n    # in the special case where the return type has been wrapped\n    # in a tuple AND its ABI type is dynamic, it expands to buf+32.\n    buf = LLLnode(buf, typ=return_t, encoding=_returndata_encoding(contract_sig), location=\"memory\")\n\n    if should_unwrap_abi_tuple:\n        buf = get_element_ptr(buf, 0, pos=None, array_bounds_check=False)\n\n    ret += [buf]\n\n    return ret, ret_ofst, ret_len\n\n\ndef _external_call_helper(\n    contract_address, contract_sig, args_lll, context, pos=None, value=None, gas=None\n):\n\n    if value is None:\n        value = 0\n    if gas is None:\n        gas = \"gas\"\n\n    # sanity check\n    assert len(contract_sig.args) == len(args_lll)\n\n    if context.is_constant() and contract_sig.mutability not in (\"view\", \"pure\"):\n        # TODO is this already done in type checker?\n        raise StateAccessViolation(\n            f\"May not call state modifying function '{contract_sig.name}' \"\n            f\"within {context.pp_constancy()}.\",\n            pos,\n        )\n\n    sub = [\"seq\"]\n\n    buf, arg_packer, args_ofst, args_len = _pack_arguments(contract_sig, args_lll, context, pos)\n\n    ret_unpacker, ret_ofst, ret_len = _unpack_returndata(buf, contract_sig, context, pos)\n\n    sub += arg_packer\n\n    if contract_sig.return_type is None:\n        # if we do not expect return data, check that a contract exists at the\n        # target address. we must perform this check BEFORE the call because\n        # the contract might selfdestruct. on the other hand we can omit this\n        # when we _do_ expect return data because we later check\n        # `returndatasize` (that check works even if the contract\n        # selfdestructs).\n        sub.append([\"assert\", [\"extcodesize\", contract_address]])\n\n    if context.is_constant() or contract_sig.mutability in (\"view\", \"pure\"):\n        call_op = [\"staticcall\", gas, contract_address, args_ofst, args_len, ret_ofst, ret_len]\n    else:\n        call_op = [\"call\", gas, contract_address, value, args_ofst, args_len, ret_ofst, ret_len]\n\n    sub.append([\"assert\", call_op])\n\n    if contract_sig.return_type is not None:\n        sub += ret_unpacker\n\n    ret = LLLnode.from_list(\n        # set the encoding to ABI here, downstream code will decode and add clampers.\n        sub,\n        typ=contract_sig.return_type,\n        location=\"memory\",\n        encoding=_returndata_encoding(contract_sig),\n        pos=pos,\n    )\n\n    return ret\n\n\n# TODO push me up to expr.py\ndef get_gas_and_value(stmt_expr, context):\n    from vyper.old_codegen.expr import Expr  # TODO rethink this circular import\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 lll_for_external_call(stmt_expr, context):\n    from vyper.old_codegen.expr import Expr  # TODO rethink this circular import\n\n    pos = getpos(stmt_expr)\n    value, gas = get_gas_and_value(stmt_expr, context)\n    args_lll = [Expr(x, context).lll_node for x in stmt_expr.args]\n\n    if isinstance(stmt_expr.func, vy_ast.Attribute) and isinstance(\n        stmt_expr.func.value, vy_ast.Call\n    ):\n        # e.g. `Foo(address).bar()`\n\n        # sanity check\n        assert len(stmt_expr.func.value.args) == 1\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    elif (\n        isinstance(stmt_expr.func.value, vy_ast.Attribute)\n        and stmt_expr.func.value.attr in context.globals\n        # TODO check for self?\n        and hasattr(context.globals[stmt_expr.func.value.attr].typ, \"name\")\n    ):\n        # e.g. `self.foo.bar()`\n\n        # sanity check\n        assert stmt_expr.func.value.value.id == \"self\", stmt_expr\n\n        contract_name = context.globals[stmt_expr.func.value.attr].typ.name\n        type_ = stmt_expr.func.value._metadata[\"type\"]\n        var = context.globals[stmt_expr.func.value.attr]\n        contract_address = unwrap_location(\n            LLLnode.from_list(\n                type_.position.position,\n                typ=var.typ,\n                location=\"storage\",\n                pos=pos,\n                annotation=\"self.\" + stmt_expr.func.value.attr,\n            )\n        )\n    else:\n        # TODO catch this during type checking\n        raise StructureException(\"Unsupported operator.\", stmt_expr)\n\n    method_name = stmt_expr.func.attr\n    contract_sig = context.sigs[contract_name][method_name]\n\n    ret = _external_call_helper(\n        contract_address,\n        contract_sig,\n        args_lll,\n        context,\n        pos,\n        value=value,\n        gas=gas,\n    )\n    ret.annotation = stmt_expr.get(\"node_source_code\")\n\n    return ret\n", "path": "vyper/old_codegen/external_call.py"}], "after_files": [{"content": "import vyper.utils as util\nfrom vyper import ast as vy_ast\nfrom vyper.exceptions import StateAccessViolation, StructureException, TypeCheckFailure\nfrom vyper.old_codegen.abi import abi_encode, abi_type_of\nfrom vyper.old_codegen.lll_node import Encoding, LLLnode\nfrom vyper.old_codegen.parser_utils import (\n    calculate_type_for_external_return,\n    get_element_ptr,\n    getpos,\n    unwrap_location,\n)\nfrom vyper.old_codegen.types import TupleType, canonicalize_type, get_type_for_exact_size\nfrom vyper.old_codegen.types.check import check_assign\n\n\ndef _pack_arguments(contract_sig, args, context, pos):\n    # abi encoding just treats all args as a big tuple\n    args_tuple_t = TupleType([x.typ for x in args])\n    args_as_tuple = LLLnode.from_list([\"multi\"] + [x for x in args], typ=args_tuple_t)\n    args_abi_t = abi_type_of(args_tuple_t)\n\n    # sanity typecheck - make sure the arguments can be assigned\n    dst_tuple_t = TupleType([arg.typ for arg in contract_sig.args][: len(args)])\n    _tmp = LLLnode(\"fake node\", location=\"memory\", typ=dst_tuple_t)\n    check_assign(_tmp, args_as_tuple, pos)\n\n    if contract_sig.return_type is not None:\n        return_abi_t = abi_type_of(calculate_type_for_external_return(contract_sig.return_type))\n\n        # we use the same buffer for args and returndata,\n        # so allocate enough space here for the returndata too.\n        buflen = max(args_abi_t.size_bound(), return_abi_t.size_bound())\n    else:\n        buflen = args_abi_t.size_bound()\n\n    buflen += 32  # padding for the method id\n\n    buf_t = get_type_for_exact_size(buflen)\n    buf = context.new_internal_variable(buf_t)\n\n    args_ofst = buf + 28\n    args_len = args_abi_t.size_bound() + 4\n\n    abi_signature = contract_sig.name + canonicalize_type(dst_tuple_t)\n\n    # layout:\n    # 32 bytes                 | args\n    # 0x..00<method_id_4bytes> | args\n    # the reason for the left padding is just so the alignment is easier.\n    # if we were only targeting constantinople, we could align\n    # to buf (and also keep code size small) by using\n    # (mstore buf (shl signature.method_id 224))\n    mstore_method_id = [[\"mstore\", buf, util.abi_method_id(abi_signature)]]\n\n    if len(args) == 0:\n        encode_args = [\"pass\"]\n    else:\n        encode_args = abi_encode(buf + 32, args_as_tuple, pos)\n\n    return buf, mstore_method_id + [encode_args], args_ofst, args_len\n\n\ndef _returndata_encoding(contract_sig):\n    if contract_sig.is_from_json:\n        return Encoding.JSON_ABI\n    return Encoding.ABI\n\n\ndef _unpack_returndata(buf, contract_sig, context, pos):\n    return_t = contract_sig.return_type\n    if return_t is None:\n        return [\"pass\"], 0, 0\n\n    return_t = calculate_type_for_external_return(return_t)\n    # if the abi signature has a different type than\n    # the vyper type, we need to wrap and unwrap the type\n    # so that the ABI decoding works correctly\n    should_unwrap_abi_tuple = return_t != contract_sig.return_type\n\n    abi_return_t = abi_type_of(return_t)\n\n    min_return_size = abi_return_t.min_size()\n    max_return_size = abi_return_t.size_bound()\n    assert 0 < min_return_size <= max_return_size\n\n    ret_ofst = buf\n    ret_len = max_return_size\n\n    # revert when returndatasize is not in bounds\n    ret = []\n    # runtime: min_return_size <= returndatasize\n    # TODO move the -1 optimization to LLL optimizer\n    ret += [[\"assert\", [\"gt\", \"returndatasize\", min_return_size - 1]]]\n\n    # add as the last LLLnode a pointer to the return data structure\n\n    # the return type has been wrapped by the calling contract;\n    # unwrap it so downstream code isn't confused.\n    # basically this expands to buf+32 if the return type has been wrapped\n    # in a tuple AND its ABI type is dynamic.\n    # in most cases, this simply will evaluate to ret.\n    # in the special case where the return type has been wrapped\n    # in a tuple AND its ABI type is dynamic, it expands to buf+32.\n    buf = LLLnode(buf, typ=return_t, encoding=_returndata_encoding(contract_sig), location=\"memory\")\n\n    if should_unwrap_abi_tuple:\n        buf = get_element_ptr(buf, 0, pos=None, array_bounds_check=False)\n\n    ret += [buf]\n\n    return ret, ret_ofst, ret_len\n\n\ndef _external_call_helper(\n    contract_address, contract_sig, args_lll, context, pos=None, value=None, gas=None\n):\n\n    if value is None:\n        value = 0\n    if gas is None:\n        gas = \"gas\"\n\n    # sanity check\n    assert len(contract_sig.base_args) <= len(args_lll) <= len(contract_sig.args)\n\n    if context.is_constant() and contract_sig.mutability not in (\"view\", \"pure\"):\n        # TODO is this already done in type checker?\n        raise StateAccessViolation(\n            f\"May not call state modifying function '{contract_sig.name}' \"\n            f\"within {context.pp_constancy()}.\",\n            pos,\n        )\n\n    sub = [\"seq\"]\n\n    buf, arg_packer, args_ofst, args_len = _pack_arguments(contract_sig, args_lll, context, pos)\n\n    ret_unpacker, ret_ofst, ret_len = _unpack_returndata(buf, contract_sig, context, pos)\n\n    sub += arg_packer\n\n    if contract_sig.return_type is None:\n        # if we do not expect return data, check that a contract exists at the\n        # target address. we must perform this check BEFORE the call because\n        # the contract might selfdestruct. on the other hand we can omit this\n        # when we _do_ expect return data because we later check\n        # `returndatasize` (that check works even if the contract\n        # selfdestructs).\n        sub.append([\"assert\", [\"extcodesize\", contract_address]])\n\n    if context.is_constant() or contract_sig.mutability in (\"view\", \"pure\"):\n        call_op = [\"staticcall\", gas, contract_address, args_ofst, args_len, ret_ofst, ret_len]\n    else:\n        call_op = [\"call\", gas, contract_address, value, args_ofst, args_len, ret_ofst, ret_len]\n\n    sub.append([\"assert\", call_op])\n\n    if contract_sig.return_type is not None:\n        sub += ret_unpacker\n\n    ret = LLLnode.from_list(\n        # set the encoding to ABI here, downstream code will decode and add clampers.\n        sub,\n        typ=contract_sig.return_type,\n        location=\"memory\",\n        encoding=_returndata_encoding(contract_sig),\n        pos=pos,\n    )\n\n    return ret\n\n\n# TODO push me up to expr.py\ndef get_gas_and_value(stmt_expr, context):\n    from vyper.old_codegen.expr import Expr  # TODO rethink this circular import\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 lll_for_external_call(stmt_expr, context):\n    from vyper.old_codegen.expr import Expr  # TODO rethink this circular import\n\n    pos = getpos(stmt_expr)\n    value, gas = get_gas_and_value(stmt_expr, context)\n    args_lll = [Expr(x, context).lll_node for x in stmt_expr.args]\n\n    if isinstance(stmt_expr.func, vy_ast.Attribute) and isinstance(\n        stmt_expr.func.value, vy_ast.Call\n    ):\n        # e.g. `Foo(address).bar()`\n\n        # sanity check\n        assert len(stmt_expr.func.value.args) == 1\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    elif (\n        isinstance(stmt_expr.func.value, vy_ast.Attribute)\n        and stmt_expr.func.value.attr in context.globals\n        # TODO check for self?\n        and hasattr(context.globals[stmt_expr.func.value.attr].typ, \"name\")\n    ):\n        # e.g. `self.foo.bar()`\n\n        # sanity check\n        assert stmt_expr.func.value.value.id == \"self\", stmt_expr\n\n        contract_name = context.globals[stmt_expr.func.value.attr].typ.name\n        type_ = stmt_expr.func.value._metadata[\"type\"]\n        var = context.globals[stmt_expr.func.value.attr]\n        contract_address = unwrap_location(\n            LLLnode.from_list(\n                type_.position.position,\n                typ=var.typ,\n                location=\"storage\",\n                pos=pos,\n                annotation=\"self.\" + stmt_expr.func.value.attr,\n            )\n        )\n    else:\n        # TODO catch this during type checking\n        raise StructureException(\"Unsupported operator.\", stmt_expr)\n\n    method_name = stmt_expr.func.attr\n    contract_sig = context.sigs[contract_name][method_name]\n\n    ret = _external_call_helper(\n        contract_address,\n        contract_sig,\n        args_lll,\n        context,\n        pos,\n        value=value,\n        gas=gas,\n    )\n    ret.annotation = stmt_expr.get(\"node_source_code\")\n\n    return ret\n", "path": "vyper/old_codegen/external_call.py"}]}