Calling `requestRedeem` with `_msgSender() != owner` will lead to user's shares being locked in the vault forever
The `requestRedeem` function in `AsyncSynthVault.sol` can be invoked by a user on behalf of another user, referred to as 'owner', provided that the user has been granted sufficient allowance by the 'owner'. However, this action results in a complete loss of balance.\\nThe `_createRedeemRequest` function contains a discrepancy; it fails to update the `lastRedeemRequestId` for the user eligible to claim the shares upon maturity. Instead, it updates this identifier for the 'owner' who delegated their shares to the user. As a result, the shares become permanently locked in the vault, rendering them unclaimable by either the 'owner' or the user.\\nThis issue unfolds as follows:\\nThe 'owner' deposits tokens into the vault, receiving vault `shares` in return.\\nThe 'owner' then delegates the allowance of all their vault `shares` to another user.\\nWhen `epochId == 1`, this user executes The `requestRedeem` , specifying the 'owner''s address as `owner`, the user's address as `receiver`, and the 'owner''s share balance as `shares`.\\nThe internal function `_createRedeemRequest` is invoked, incrementing `epochs[epochId].redeemRequestBalance[receiver]` by the amount of `shares`, and setting `lastRedeemRequestId[owner] = epochId`.\\nAt `epochId == 2`, the user calls `claimRedeem`, which in turn calls the internal function `_claimRedeem`, with `owner` set to `_msgSender()` (i.e., the user's address) and `receiver` also set to the user's address.\\nIn this scenario, `lastRequestId` remains zero because `lastRedeemRequestId[owner] == 0` (here, `owner` refers to the user's address). Consequently, `epochs[lastRequestId].redeemRequestBalance[owner]` is also zero. Therefore, no `shares` are minted to the user.\\nProof of Code :\\nThe following test demonstrates the claim made above :\\n```\\nfunction test_poc() external {\\n        // set token balances\\n        deal(vaultTested.asset(), user1.addr, 20); // owner\\n\\n        vm.startPrank(user1.addr);\\n        IERC20Metadata(vaultTested.asset()).approve(address(vaultTested), 20);\\n        // owner deposits tokens when vault is open and receives vault shares\\n        vaultTested.deposit(20, user1.addr);\\n        // owner delegates shares balance to user\\n        IERC20Metadata(address(vaultTested)).approve(\\n            user2.addr,\\n            vaultTested.balanceOf(user1.addr)\\n        );\\n        vm.stopPrank();\\n\\n        // vault is closed\\n        vm.prank(vaultTested.owner());\\n        vaultTested.close();\\n\\n        // epoch = 1\\n        vm.startPrank(user2.addr);\\n        // user requests a redeem on behlaf of owner\\n        vaultTested.requestRedeem(\\n            vaultTested.balanceOf(user1.addr),\\n            user2.addr,\\n            user1.addr,\\n            ""\\n        );\\n        // user checks the pending redeem request amount\\n        assertEq(vaultTested.pendingRedeemRequest(user2.addr), 20);\\n        vm.stopPrank();\\n\\n        vm.startPrank(vaultTested.owner());\\n        IERC20Metadata(vaultTested.asset()).approve(\\n            address(vaultTested),\\n            type(uint256).max\\n        );\\n        vaultTested.settle(23); // an epoch goes by\\n        vm.stopPrank();\\n\\n        // epoch = 2\\n\\n        vm.startPrank(user2.addr);\\n        // user tries to claim the redeem\\n        vaultTested.claimRedeem(user2.addr);\\n        assertEq(IERC20Metadata(vaultTested.asset()).balanceOf(user2.addr), 0);\\n        // however, token balance of user is still empty\\n        vm.stopPrank();\\n\\n        vm.startPrank(user1.addr);\\n        // owner also tries to claim the redeem\\n        vaultTested.claimRedeem(user1.addr);\\n        assertEq(IERC20Metadata(vaultTested.asset()).balanceOf(user1.addr), 0);\\n        // however, token balance of owner is still empty\\n        vm.stopPrank();\\n\\n        // all the balances of owner and user are zero, indicating loss of funds\\n        assertEq(vaultTested.balanceOf(user1.addr), 0);\\n        assertEq(IERC20Metadata(vaultTested.asset()).balanceOf(user1.addr), 0);\\n        assertEq(vaultTested.balanceOf(user2.addr), 0);\\n        assertEq(IERC20Metadata(vaultTested.asset()).balanceOf(user2.addr), 0);\\n    }\\n```\\n\\nTo run the test :\\nCopy the above code and paste it into `TestClaimDeposit.t.sol`\\nRun `forge test --match-test test_poc --ffi`
Modify `_createRedeemRequest` as follows :\\n```\\n// Remove the line below\\n        lastRedeemRequestId[owner] = epochId;\\n// Add the line below\\n       lastRedeemRequestid[receiver] = epochId;\\n```\\n
The shares are locked in the vault forever with no method for recovery by the user or the 'owner'.
```\\nfunction test_poc() external {\\n        // set token balances\\n        deal(vaultTested.asset(), user1.addr, 20); // owner\\n\\n        vm.startPrank(user1.addr);\\n        IERC20Metadata(vaultTested.asset()).approve(address(vaultTested), 20);\\n        // owner deposits tokens when vault is open and receives vault shares\\n        vaultTested.deposit(20, user1.addr);\\n        // owner delegates shares balance to user\\n        IERC20Metadata(address(vaultTested)).approve(\\n            user2.addr,\\n            vaultTested.balanceOf(user1.addr)\\n        );\\n        vm.stopPrank();\\n\\n        // vault is closed\\n        vm.prank(vaultTested.owner());\\n        vaultTested.close();\\n\\n        // epoch = 1\\n        vm.startPrank(user2.addr);\\n        // user requests a redeem on behlaf of owner\\n        vaultTested.requestRedeem(\\n            vaultTested.balanceOf(user1.addr),\\n            user2.addr,\\n            user1.addr,\\n            ""\\n        );\\n        // user checks the pending redeem request amount\\n        assertEq(vaultTested.pendingRedeemRequest(user2.addr), 20);\\n        vm.stopPrank();\\n\\n        vm.startPrank(vaultTested.owner());\\n        IERC20Metadata(vaultTested.asset()).approve(\\n            address(vaultTested),\\n            type(uint256).max\\n        );\\n        vaultTested.settle(23); // an epoch goes by\\n        vm.stopPrank();\\n\\n        // epoch = 2\\n\\n        vm.startPrank(user2.addr);\\n        // user tries to claim the redeem\\n        vaultTested.claimRedeem(user2.addr);\\n        assertEq(IERC20Metadata(vaultTested.asset()).balanceOf(user2.addr), 0);\\n        // however, token balance of user is still empty\\n        vm.stopPrank();\\n\\n        vm.startPrank(user1.addr);\\n        // owner also tries to claim the redeem\\n        vaultTested.claimRedeem(user1.addr);\\n        assertEq(IERC20Metadata(vaultTested.asset()).balanceOf(user1.addr), 0);\\n        // however, token balance of owner is still empty\\n        vm.stopPrank();\\n\\n        // all the balances of owner and user are zero, indicating loss of funds\\n        assertEq(vaultTested.balanceOf(user1.addr), 0);\\n        assertEq(IERC20Metadata(vaultTested.asset()).balanceOf(user1.addr), 0);\\n        assertEq(vaultTested.balanceOf(user2.addr), 0);\\n        assertEq(IERC20Metadata(vaultTested.asset()).balanceOf(user2.addr), 0);\\n    }\\n```\\n