diff --git a/contracts/persistent/shares-wrappers/gated-redemption-queue/GatedRedemptionQueueSharesWrapperLib.sol b/contracts/persistent/shares-wrappers/gated-redemption-queue/GatedRedemptionQueueSharesWrapperLib.sol index e901a795f..19bd99d99 100644 --- a/contracts/persistent/shares-wrappers/gated-redemption-queue/GatedRedemptionQueueSharesWrapperLib.sol +++ b/contracts/persistent/shares-wrappers/gated-redemption-queue/GatedRedemptionQueueSharesWrapperLib.sol @@ -361,8 +361,12 @@ contract GatedRedemptionQueueSharesWrapperLib is GatedRedemptionQueueSharesWrapp /// @dev Helper to remove a deposit request from the queue function __removeDepositRequest(address _user, address _depositAsset) private { DepositQueue storage queue = depositAssetToQueue[_depositAsset]; - uint256 queueLength = queue.users.length; + + // Validate that a request exists for the _user + require(queue.userToRequest[_user].assetAmount > 0, "__removeDepositRequest: No request"); + uint256 userIndex = queue.userToRequest[_user].index; + uint256 queueLength = queue.users.length; if (userIndex < queueLength - 1) { address userToMove = queue.users[queueLength - 1]; diff --git a/packages/protocol/tests/persistent/shares-wrappers/GatedRedemptionQueueSharesWrapper.test.ts b/packages/protocol/tests/persistent/shares-wrappers/GatedRedemptionQueueSharesWrapper.test.ts index ef4fb1d32..76781042f 100644 --- a/packages/protocol/tests/persistent/shares-wrappers/GatedRedemptionQueueSharesWrapper.test.ts +++ b/packages/protocol/tests/persistent/shares-wrappers/GatedRedemptionQueueSharesWrapper.test.ts @@ -386,6 +386,16 @@ describe('investment flow', () => { }); describe('cancelRequestDeposit', () => { + it('cannot be called for a user without a request', async () => { + // Add one user to the queue (so there is a valid request at index 0) + await sharesWrapper.connect(investor1).requestDeposit(denominationAsset, denominationAssetUnit); + + // Cancel from a user with no request + await expect( + sharesWrapper.connect(randomUser).cancelRequestDeposit(denominationAsset), + ).rejects.toBeRevertedWith('No request'); + }); + it('happy path', async () => { const deposit1Amount = denominationAssetUnit.mul(11); const deposit2Amount = denominationAssetUnit.mul(3); @@ -486,6 +496,12 @@ describe('investment flow', () => { }); describe('depositFromQueue', () => { + it('cannot be called for a user without a request', async () => { + await expect( + sharesWrapper.connect(manager).depositFromQueue(denominationAsset, [randomUser]), + ).rejects.toBeRevertedWith('No request'); + }); + it('happy path: single user, middle of queue', async () => { // Most logic tested during depositAllFromQueue. Only test queue removal here.