From 5f5b2015e4d416683e7c80036b179d4973490c7e Mon Sep 17 00:00:00 2001 From: pdobacz <5735525+pdobacz@users.noreply.github.com> Date: Thu, 3 Sep 2026 15:12:02 +0000 Subject: [PATCH] test a reserve balance violation reverting with its call frame Covers the debiting frame and its enclosing frame unwinding, against the frame returning normally. Co-Authored-By: Claude --- .../reserve_balance/test_transfers.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/monad_eight/reserve_balance/test_transfers.py b/tests/monad_eight/reserve_balance/test_transfers.py index 5a06d5b19ce..1ac29a5c2aa 100644 --- a/tests/monad_eight/reserve_balance/test_transfers.py +++ b/tests/monad_eight/reserve_balance/test_transfers.py @@ -1115,6 +1115,58 @@ def test_credit_after_call_frame( ) +@pytest.mark.parametrize( + "exit_op", + [Op.STOP, Op.RETURN(0, 0), Op.REVERT(0, 0), Op.INVALID], +) +@pytest.mark.parametrize("enclosing_frame_reverts", [True, False]) +def test_violating_call_frame_rolled_back( + blockchain_test: BlockchainTestFiller, + pre: Alloc, + exit_op: Bytecode, + enclosing_frame_reverts: bool, + fork: Fork, +) -> None: + """ + Test that a reserve balance violation reverts with the frame. + """ + sink_address = pre.deploy_contract(Op.STOP) + wallet_address = pre.deploy_contract( + Op.CALL(address=sink_address, value=1) + exit_op + ) + sender = pre.fund_eoa(Spec.RESERVE_BALANCE, delegation=wallet_address) + + debiting_call = Op.CALL(address=sender) + if enclosing_frame_reverts: + debiting_call = Op.CALL( + address=pre.deploy_contract(debiting_call + Op.REVERT(0, 0)) + ) + + contract_address = pre.deploy_contract( + Op.SSTORE(slot_code_worked, value_code_worked) + debiting_call + ) + + tx_1 = Transaction( + gas_limit=generous_gas(fork), + to=contract_address, + sender=pre.fund_eoa(), + ) + + debit_survives = exit_op in (Op.STOP, Op.RETURN(0, 0)) + reverted = debit_survives and not enclosing_frame_reverts + storage = {} if reverted else {slot_code_worked: value_code_worked} + + blockchain_test( + pre=pre, + post={ + contract_address: Account(storage=storage), + sender: Account(balance=Spec.RESERVE_BALANCE), + sink_address: Account(balance=0), + }, + blocks=[Block(txs=[tx_1])], + ) + + @pytest.mark.parametrize( ["value", "balance", "violation"], [