diff --git a/src/RoboSaverVirtualModule.sol b/src/RoboSaverVirtualModule.sol index fd64916..3b9a0d9 100644 --- a/src/RoboSaverVirtualModule.sol +++ b/src/RoboSaverVirtualModule.sol @@ -537,8 +537,13 @@ contract RoboSaverVirtualModule is /// @param _target The address of the target of the transaction /// @param _payload The payload of the transaction function _queueTx(address _target, bytes memory _payload) internal { - /// @dev since all actions go through multicall3, operation is set to 1 (DelegateCall) - delayModule.execTransactionFromModule(_target, 0, _payload, 1); + /// @dev the newest action is leading; if we already have a transaction queued up we should skip it + if (queuedTx.nonce != 0) { + delayModule.setTxNonce(queuedTx.nonce); + delete queuedTx; + } + + delayModule.execTransactionFromModule(_target, 0, _payload, OPERATION_DELEGATECALL); uint256 cachedQueueNonce = delayModule.queueNonce(); queuedTx = VirtualModule.QueuedTx(cachedQueueNonce, _target, _payload); diff --git a/src/abstracts/RoboSaverConstants.sol b/src/abstracts/RoboSaverConstants.sol index e2f9b44..d2dc3af 100644 --- a/src/abstracts/RoboSaverConstants.sol +++ b/src/abstracts/RoboSaverConstants.sol @@ -9,8 +9,8 @@ import "@balancer-v2/interfaces/contracts/vault/IVault.sol"; import "@balancer-v2/interfaces/contracts/solidity-utils/misc/IERC4626.sol"; abstract contract RoboSaverConstants { + uint8 constant OPERATION_DELEGATECALL = 1; uint16 constant MAX_BPS = 10_000; - uint256 constant EURE_TOKEN_BPT_INDEX = 2; uint256 constant EURE_TOKEN_BPT_INDEX_USER = 1; uint256 constant MODULE_PAGE_SIZE = 1; diff --git a/test/regression/CornerCaseV0_1_0Test.t.sol b/test/regression/CornerCaseV0_1_0Test.t.sol new file mode 100644 index 0000000..797accb --- /dev/null +++ b/test/regression/CornerCaseV0_1_0Test.t.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.25; + +import {BaseFixture} from "../BaseFixture.sol"; + +import {VirtualModule} from "../../src/types/DataTypes.sol"; + +/// @notice This file is for testing the corner cases that were faced during v0.1.0 tests-run +/// and face minor challenges which should be always fixed and gracefully handled on `>v0.1.0` +contract CornerCaseV0_1_0Test is BaseFixture { + function test_DepositAndShutdownBlockage() public { + // 1. encounter condition where naturally a deposit is being queued + _incomingEure(1_000e18); + uint256 surplus = roboModule.surplus(); + assertGt(surplus, 0); + + _upkeepAndAssertPayload(abi.encode(VirtualModule.PoolAction.DEPOSIT, surplus)); + + (uint256 nonceDepositTx,, bytes memory payloadDepositTx) = roboModule.queuedTx(); + assertEq(nonceDepositTx, 1); + + // 2. admin of the virtual module decides to `shutdown()` while initial queue tx is on cooldown phase still + vm.prank(roboModule.CARD()); + roboModule.shutdown(); + + // 3. Internal payload should not have being override, otherwise initial deposit never can be executed + (uint256 nonceShutdownTx,, bytes memory payloadShutdownTx) = roboModule.queuedTx(); + + // @note if it not identical a blockage will be suffer and force to wait for tx expiration + assertEq(nonceDepositTx, nonceShutdownTx); + assertEq(payloadDepositTx, payloadShutdownTx); + } +}