@@ -743,6 +743,97 @@ func TestClaimWithdrawalInvalidRequestId(t *testing.T) {
743743 assert .Contains (t , err .Error (), "not found" )
744744}
745745
746+ func TestClaimWithdrawalInsufficientLocalFunds (t * testing.T ) {
747+ k , vaultsV2Server , bank , ctx , bob := setupV2Test (t )
748+
749+ // ARRANGE: Deposit and request withdrawal
750+ require .NoError (t , k .Mint (ctx , bob .Bytes , math .NewInt (100 * ONE_V2 ), nil ))
751+ _ , err := vaultsV2Server .Deposit (ctx , & vaultsv2.MsgDeposit {
752+ Depositor : bob .Address ,
753+ Amount : math .NewInt (100 * ONE_V2 ),
754+ ReceiveYield : true ,
755+ })
756+ require .NoError (t , err )
757+
758+ resp , err := vaultsV2Server .RequestWithdrawal (ctx , & vaultsv2.MsgRequestWithdrawal {
759+ Requester : bob .Address ,
760+ PositionId : 1 ,
761+ Amount : math .NewInt (50 * ONE_V2 ),
762+ })
763+ require .NoError (t , err )
764+
765+ // ARRANGE: Move time forward and process queue to mark withdrawal as READY
766+ ctx = ctx .WithHeaderInfo (header.Info {Time : time .Date (2024 , 1 , 2 , 1 , 0 , 0 , 0 , time .UTC )})
767+ _ , err = vaultsV2Server .ProcessWithdrawalQueue (ctx , & vaultsv2.MsgProcessWithdrawalQueue {
768+ Authority : "authority" ,
769+ MaxRequests : 10 ,
770+ })
771+ require .NoError (t , err )
772+
773+ // ARRANGE: Store initial state before reducing LocalFunds
774+ positionBefore , found , err := k .GetVaultsV2UserPosition (ctx , bob .Bytes , 1 )
775+ require .NoError (t , err )
776+ require .True (t , found )
777+
778+ requestBefore , found , err := k .GetVaultsV2Withdrawal (ctx , resp .RequestId )
779+ require .NoError (t , err )
780+ require .True (t , found )
781+
782+ stateBefore , err := k .GetVaultsV2VaultState (ctx )
783+ require .NoError (t , err )
784+
785+ // ARRANGE: Reduce LocalFunds to be less than withdrawal amount
786+ // LocalFunds is currently 100, reduce by 70 to leave only 30 (< 50 withdrawal amount)
787+ require .NoError (t , k .SubtractVaultsV2LocalFunds (ctx , math .NewInt (70 * ONE_V2 )))
788+ localFundsBeforeClaim , err := k .GetVaultsV2LocalFunds (ctx )
789+ require .NoError (t , err )
790+ assert .Equal (t , math .NewInt (30 * ONE_V2 ), localFundsBeforeClaim )
791+
792+ // ACT: Attempt to claim withdrawal with insufficient LocalFunds
793+ _ , err = vaultsV2Server .ClaimWithdrawal (ctx , & vaultsv2.MsgClaimWithdrawal {
794+ Claimer : bob .Address ,
795+ RequestId : resp .RequestId ,
796+ })
797+
798+ // ASSERT: Claim fails with ErrInsufficientLocalFunds
799+ require .Error (t , err )
800+ require .ErrorIs (t , err , vaultsv2 .ErrInsufficientLocalFunds )
801+
802+ // ASSERT: Withdrawal request still exists and is still READY
803+ requestAfter , found , err := k .GetVaultsV2Withdrawal (ctx , resp .RequestId )
804+ require .NoError (t , err )
805+ require .True (t , found )
806+ assert .Equal (t , requestBefore .Status , requestAfter .Status )
807+ assert .Equal (t , vaultsv2 .WITHDRAWAL_REQUEST_STATUS_READY , requestAfter .Status )
808+
809+ // ASSERT: User position unchanged
810+ positionAfter , found , err := k .GetVaultsV2UserPosition (ctx , bob .Bytes , 1 )
811+ require .NoError (t , err )
812+ require .True (t , found )
813+ assert .Equal (t , positionBefore .DepositPendingWithdrawal , positionAfter .DepositPendingWithdrawal )
814+ assert .Equal (t , positionBefore .YieldPendingWithdrawal , positionAfter .YieldPendingWithdrawal )
815+ assert .Equal (t , positionBefore .TotalPendingWithdrawal , positionAfter .TotalPendingWithdrawal )
816+ assert .Equal (t , positionBefore .ActiveWithdrawalRequests , positionAfter .ActiveWithdrawalRequests )
817+ assert .Equal (t , positionBefore .DepositAmount , positionAfter .DepositAmount )
818+ assert .Equal (t , positionBefore .AccruedYield , positionAfter .AccruedYield )
819+
820+ // ASSERT: LocalFunds unchanged (still 30)
821+ localFundsAfter , err := k .GetVaultsV2LocalFunds (ctx )
822+ require .NoError (t , err )
823+ assert .Equal (t , math .NewInt (30 * ONE_V2 ), localFundsAfter )
824+
825+ // ASSERT: No coins transferred to user
826+ assert .Equal (t , math .ZeroInt (), bank .Balances [bob .Address ].AmountOf ("uusdn" ))
827+
828+ // ASSERT: Vault state unchanged
829+ stateAfter , err := k .GetVaultsV2VaultState (ctx )
830+ require .NoError (t , err )
831+ assert .Equal (t , stateBefore .PendingWithdrawalRequests , stateAfter .PendingWithdrawalRequests )
832+ assert .Equal (t , stateBefore .TotalDepositPendingWithdrawal , stateAfter .TotalDepositPendingWithdrawal )
833+ assert .Equal (t , stateBefore .TotalYieldPendingWithdrawal , stateAfter .TotalYieldPendingWithdrawal )
834+ assert .Equal (t , stateBefore .TotalPendingWithdrawal , stateAfter .TotalPendingWithdrawal )
835+ }
836+
746837func TestFullDepositWithdrawalCycle (t * testing.T ) {
747838 k , vaultsV2Server , bank , ctx , bob := setupV2Test (t )
748839
0 commit comments