@@ -669,6 +669,69 @@ describe("PerpV2LeverageSlippageIssuance", () => {
669
669
expect ( toUSDCDecimals ( finalCollateralBalance ) ) . to . be . closeTo ( expectedCollateralBalance , 2 ) ;
670
670
} ) ;
671
671
} ) ;
672
+
673
+ describe ( "when liquidation results in negative account value" , ( ) => {
674
+ beforeEach ( async ( ) => {
675
+ subjectQuantity = ether ( 1 ) ;
676
+
677
+ // Calculated leverage = ~8.5X = 8_654_438_822_995_683_587
678
+ await leverUp (
679
+ setToken ,
680
+ perpLeverageModule ,
681
+ perpSetup ,
682
+ owner ,
683
+ baseToken ,
684
+ 6 ,
685
+ ether ( .02 ) ,
686
+ true
687
+ ) ;
688
+
689
+ // Move oracle price down to 5 USDC to enable liquidation
690
+ await perpSetup . setBaseTokenOraclePrice ( vETH , usdcUnits ( 5 ) ) ;
691
+
692
+ // Move price down by maker selling 20_000 USDC of vETH
693
+ // Post trade spot price drops from ~10 USDC to 6_380_562_015_950_425_028
694
+ await perpSetup . clearingHouse . connect ( maker . wallet ) . openPosition ( {
695
+ baseToken : vETH . address ,
696
+ isBaseToQuote : true , // short
697
+ isExactInput : false , // `amount` is USDC
698
+ amount : ether ( 20_000 ) ,
699
+ oppositeAmountBound : ZERO ,
700
+ deadline : MAX_UINT_256 ,
701
+ sqrtPriceLimitX96 : ZERO ,
702
+ referralCode : ZERO_BYTES
703
+ } ) ;
704
+
705
+ await perpSetup
706
+ . clearingHouse
707
+ . connect ( otherTrader . wallet )
708
+ . liquidate ( subjectSetToken , baseToken ) ;
709
+ } ) ;
710
+
711
+ // In this test case, the account is bankrupt:
712
+ // collateralBalance = 10050000000000000000
713
+ // owedRealizedPnl = -31795534271984084912
714
+ it ( "should issue without transferring any usdc (because account worth 0)" , async ( ) => {
715
+ const issueQuantityWithFees = ( await slippageIssuanceModule . calculateTotalFees (
716
+ subjectSetToken ,
717
+ subjectQuantity ,
718
+ true
719
+ ) ) [ 0 ] ;
720
+
721
+ const initialIssuerUSDCBalance = await usdc . balanceOf ( subjectCaller . address ) ;
722
+ const initialTotalSupply = await setToken . totalSupply ( ) ;
723
+
724
+ await subject ( ) ;
725
+
726
+ const finalIssuerUSDCBalance = await usdc . balanceOf ( subjectCaller . address ) ;
727
+ const finalTotalSupply = await setToken . totalSupply ( ) ;
728
+
729
+ const expectedTotalSupply = initialTotalSupply . add ( issueQuantityWithFees ) ;
730
+
731
+ expect ( finalTotalSupply ) . eq ( expectedTotalSupply ) ;
732
+ expect ( finalIssuerUSDCBalance ) . eq ( initialIssuerUSDCBalance ) ;
733
+ } ) ;
734
+ } ) ;
672
735
} ) ;
673
736
} ) ;
674
737
@@ -1209,6 +1272,30 @@ describe("PerpV2LeverageSlippageIssuance", () => {
1209
1272
. liquidate ( subjectSetToken , baseToken ) ;
1210
1273
} ) ;
1211
1274
1275
+ // In this test case, the account is bankrupt:
1276
+ // collateralBalance = 10050000000000000000
1277
+ // owedRealizedPnl = -31795534271984084912
1278
+ it ( "should redeem without transferring any usdc (because account worth 0)" , async ( ) => {
1279
+ const redeemQuantityWithFees = ( await slippageIssuanceModule . calculateTotalFees (
1280
+ subjectSetToken ,
1281
+ subjectQuantity ,
1282
+ false
1283
+ ) ) [ 0 ] ;
1284
+
1285
+ const initialRedeemerUSDCBalance = await usdc . balanceOf ( subjectCaller . address ) ;
1286
+ const initialTotalSupply = await setToken . totalSupply ( ) ;
1287
+
1288
+ await subject ( ) ;
1289
+
1290
+ const finalRedeemerUSDCBalance = await usdc . balanceOf ( subjectCaller . address ) ;
1291
+ const finalTotalSupply = await setToken . totalSupply ( ) ;
1292
+
1293
+ const expectedTotalSupply = initialTotalSupply . sub ( redeemQuantityWithFees ) ;
1294
+
1295
+ expect ( finalTotalSupply ) . eq ( expectedTotalSupply ) ;
1296
+ expect ( finalRedeemerUSDCBalance ) . eq ( initialRedeemerUSDCBalance ) ;
1297
+ } ) ;
1298
+
1212
1299
it ( "should be possible to remove the module" , async ( ) => {
1213
1300
await subject ( ) ;
1214
1301
0 commit comments