Company Simulator

First Flight #51
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Invalid staticcall usage breaks reputation check (compilation / correctness)

Root + Impact

Description

  • Expected behavior: The CustomerEngine should call reputation() on the CompanyGame contract using valid Vyper syntax so the reputation check executes at runtime. A correct inter-contract view call should compile and return the reputation value.

  • Actual behavior: The code uses a staticcall-style expression that is not valid Vyper syntax: # (from supplied CustomerEngine.vy)

    rep: uint256 = staticcall CompanyGame(self.company).reputation()


// Root cause in the codebase with @> marks to highlight the relevant section# Reputation check (incorrect)
@> rep: uint256 = staticcall CompanyGame(self.company).reputation()
@> assert rep >= MIN_REPUTATION, "Reputation too low for demand!!!"

Risk

Likelihood

High: This is a clear syntactic/semantic error that will surface at compile time if not fixed.

Impact

1.High: The contract may fail to compile (blocking deployment), or if compiled with a changed implementation the reputation check may be bypassed, allowing low-reputation demand to proceed.

2.Functional break: CustomerEngine cannot safely gate demand by reputation, impacting economic simulation and allowing unvalidated sales.

Proof of Concept

Explanation

Vyper uses interface calls like CompanyGame(self.company).reputation() to perform external view calls. staticcall is a low-level EVM operation; in Vyper you either call the interface method directly (preferred) or use raw_call and decode the returned bytes. Mixing staticcall with the interface syntax is invalid.

Leaving the line as-is results in a compiler error (deployment blocked) or in developers substituting incorrect logic that bypasses reputation checks — both are unacceptable.

# PoC_invalid_staticcall.vy
# @version ^0.4.1
interface CompanyGame:
def reputation() -> uint256: view
company: public(address)
@external
def bad_call():
# invalid Vyper syntax — this line is intentionally wrong to show the issue
rep: uint256 = staticcall CompanyGame(self.company).reputation()
assert rep >= 60

Recommended Mitigation

Replace the invalid staticcall expression with a proper Vyper interface call

Or

Option B — Defensive | Use raw_call and validate returned bytes (if the counterparty may be non-conforming):

- remove this code
+ add this code
- rep: uint256 = staticcall CompanyGame(self.company).reputation()
+ rep: uint256 = CompanyGame(self.company).reputation()
#Option B
- rep: uint256 = staticcall CompanyGame(self.company).reputation()
+ # conservative: perform a low-level call and decode to guard against strange implementations
+ data: Bytes[32] = raw_call(
+ self.company,
+ method_id("reputation()"),
+ max_outsize=32,
+ revert_on_failure=False
+ )
+ assert len(data) == 32, "reputation call failed"
+ rep: uint256 = convert(data, uint256)
Updates

Lead Judging Commences

0xshaedyw Lead Judge
5 days ago
0xshaedyw Lead Judge 4 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.