From 4a01439f27fd2dbb3bde79041ce653bb04102772 Mon Sep 17 00:00:00 2001 From: lukezed Date: Wed, 20 May 2026 22:03:52 +0100 Subject: [PATCH] Prevent zero-asset withdrawals --- src/tenderizer/Tenderizer.sol | 1 + test/tenderizer/Tenderizer.t.sol | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/tenderizer/Tenderizer.sol b/src/tenderizer/Tenderizer.sol index c211f56..2570278 100644 --- a/src/tenderizer/Tenderizer.sol +++ b/src/tenderizer/Tenderizer.sol @@ -124,6 +124,7 @@ contract Tenderizer is TenderizerImmutableArgs, TenderizerEvents, TToken, Multic // withdraw assets to send to `receiver` amount = _withdraw(validator(), unlockID); + if (amount == 0) revert InsufficientAssets(); // transfer assets to `receiver` ERC20(asset()).safeTransfer(receiver, amount); diff --git a/test/tenderizer/Tenderizer.t.sol b/test/tenderizer/Tenderizer.t.sol index 4155a1b..f8e10d6 100644 --- a/test/tenderizer/Tenderizer.t.sol +++ b/test/tenderizer/Tenderizer.t.sol @@ -17,6 +17,7 @@ import { StdCheats } from "forge-std/StdCheats.sol"; import { IERC20, IERC20Metadata } from "core/interfaces/IERC20.sol"; import { Adapter, TenderizerHarness } from "test/tenderizer/Tenderizer.harness.sol"; import { AdapterDelegateCall } from "core/adapters/Adapter.sol"; +import { Tenderizer as TenderizerContract } from "core/tenderizer/Tenderizer.sol"; import { TenderizerEvents } from "core/tenderizer/TenderizerBase.sol"; import { StaticCallFailed } from "core/utils/StaticCall.sol"; import { TToken } from "core/tendertoken/TToken.sol"; @@ -298,6 +299,16 @@ contract TenderizerTest is TenderizerSetup, TenderizerEvents { tenderizer.withdraw(account1, unlockID); } + function test_Withdraw_RevertIfAdapterReturnsZeroAssets() public { + uint256 unlockID = 1; + vm.mockCall(unlocks, abi.encodeCall(Unlocks.useUnlock, (account1, unlockID)), ""); + vm.mockCall(adapter, abi.encodeCall(Adapter.withdraw, (validator, unlockID)), abi.encode(0)); + + vm.prank(account1); + vm.expectRevert(TenderizerContract.InsufficientAssets.selector); + tenderizer.withdraw(account2, unlockID); + } + function test_Withdraw_RevertIfUseUnlockFails() public { uint256 unlockID = 1; // Calls to mocked addresses may revert if there is no code on the address.