Describe the normal behavior in one or more sentences
Normal behavior: Users submitting openPosition or unwindPosition may assume their transaction will run with the implementation that was current when they signed or submitted it. In-flight transactions would complete against the old logic.
The proxy does not pin the implementation for in-flight transactions. The implementation is resolved at execution time on every call. When the beacon is updated before a user's transaction is mined, that transaction runs against the new implementation. BeaconProxy does not cache the implementation address; each external call invokes _implementation(), which reads from the beacon. So the code that runs is whatever the beacon returns at the moment the call is executed. In-flight open/unwind transactions do not complete safely against the old logic—they can execute against the new implementation mid-flight.
Likelihood:
Upgrades occur without a timelock, so the beacon can be updated at any time. Any pending open/unwind transaction in the mempool or in a later block will use the implementation current at execution time.
Block ordering and MEV allow the beacon owner's upgrade transaction to be mined in the same block or before a user's already-submitted transaction, so the user's call runs against the new implementation.
Impact:
A malicious or buggy new implementation can steal funds, change fees, or alter behavior so that the user's open/unwind does something they did not intend. The user signed for one set of semantics but execution uses another.
A new implementation with different storage layout or function semantics can cause the in-flight call to revert, leave storage inconsistent, or corrupt state, leading to stuck positions or loss of funds.
Users and integrators may assume in-flight txs complete against the old logic; that guarantee does not hold. With no timelock, there is no on-chain window to cancel or avoid execution under the new implementation.
The PoC shows that the implementation is resolved at execution time. We upgrade the beacon to a new implementation, then call the proxy in the same test. The proxy's next call is served by the new implementation—there is no pinning to the implementation that was current when the "logical" request was made. This simulates an in-flight tx: a user's transaction that is executed after an upgrade runs against the new implementation. Run: forge test --match-contract PoC_InFlightTxNewImplementation -vvv.
Use a timelock as the beacon owner so upgrades take effect only after a delay, giving users time to avoid submitting new txs or to exit before the new implementation is active. Document that the implementation is resolved at execution time and that pending txs are not pinned to the implementation current at submit time.
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.
The contest is complete and the rewards are being distributed.