The CustomerEngine.vy contract's trigger_demand() function is responsible for initiating a sale and handling ETH transfers. When a customer calls this function, they must send the full purchase price (msg.value).
The function first refunds any excess ETH to the customer. It then makes a raw_call to Cyfrin_Hub.sell_to_customer with the calculated sale price.
If the sell_to_customer call fails (e.g., due to zero inventory, as confirmed by PoC), the raw_call reverts, but the ETH sent with the raw_call is returned to the CustomerEngine contract's balance. Since the CustomerEngine has no withdrawal function, this ETH becomes permanently stuck in the contract.
Likelihood: Medium
The exploit occurs under a specific, but common, condition: the Cyfrin_Hub must revert a sale. This happens whenever the company has zero inventory, which is a normal operational state (e.g., between production cycles). The attacker only needs to call the function when inventory is low to cause the revert and stick the ETH.
Impact: Medium
The amount of stuck ETH is limited to the sale price (price) for that specific transaction. While the protocol's core funds are not at risk, the contract's balance will accumulate stuck funds over time, leading to a loss of revenue for the company and an unexpected loss for the customer (who expects the sale to succeed or the funds to be returned).
The exploit was confirmed by a targeted PoC test:
Setup: Deploy contracts. Owner funds Hub but does not produce inventory.
Attack: Customer calls trigger_demand() with 1 ETH. Sale price is 0.02 ETH.
Execution:
CustomerEngine refunds 0.98 ETH (excess).
CustomerEngine calls sell_to_customer with 0.02 ETH.
sell_to_customer reverts due to zero inventory.
The 0.02 ETH is returned to the CustomerEngine contract.
Result: The CustomerEngine contract's balance increases by 0.02 ETH, which is now permanently stuck.
Supporting Code:
The CustomerEngine must check the result of the raw_call and, if it fails, refund the price ETH back to the msg.sender.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.