Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions tests/functional/builtins/codegen/test_raw_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,25 @@ def foo(_addr: address):
""",
TypeMismatch,
),
(
"""
@pure
@external
def foo(a: address):
# test staticcall detection from pure function
x: Bytes[32] = raw_call(a, b'', max_outsize=32, is_static_call=True)
""",
StateAccessViolation,
),
(
"""
@pure
def foo(a: address):
# test staticcall detection from pure function with constant folding
x: Bytes[32] = raw_call(a, b'', max_outsize=32, is_static_call=True or False)
""",
StateAccessViolation,
),
]


Expand Down
12 changes: 12 additions & 0 deletions vyper/builtins/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,18 @@ def infer_arg_types(self, node, expected_return_typ=None):
data_type = get_possible_types_from_node(node.args[1]).pop()
return [self._inputs[0][1], data_type]

# get the mutability, which is determined at a specific call site
def get_mutability_at_call_site(self, node: vy_ast.Call):
kw = {k.arg: k.value for k in node.keywords}

is_static = kw.get("is_static_call", None)
is_static = is_static.get_folded_value() if is_static else False

if is_static:
return StateMutability.VIEW

return StateMutability.NONPAYABLE

@process_inputs
def build_IR(self, expr, args, kwargs, context):
to, data = args
Expand Down
11 changes: 10 additions & 1 deletion vyper/semantics/analysis/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,16 @@ def visit_Call(self, node: vy_ast.Call, typ: VyperType) -> None:
else:
# builtin functions and interfaces
if self.function_analyzer and hasattr(func_type, "mutability"):
self._check_call_mutability(func_type.mutability) # type: ignore
from vyper.builtins.functions import RawCall

if isinstance(func_type, RawCall):
# as opposed to other functions, raw_call's mutability
# depends on its arguments, so we need to determine
# it at each call site.
mutability = func_type.get_mutability_at_call_site(node)
else:
mutability = func_type.mutability
self._check_call_mutability(mutability) # type: ignore

arg_types = func_type.infer_arg_types(node, expected_return_typ=typ) # type: ignore
for arg, arg_type in zip(node.args, arg_types):
Expand Down