@@ -464,87 +464,14 @@ fun testLiquidateMultiCollateralChooseUSDC() {
464464// Scenario 1: DEX vault funded with 23 USDF (50% of 46 needed) -> liquidation reverts
465465// Scenario 2: top up to 53 USDF (>=46) -> liquidation succeeds
466466// =============================================================================
467- access (all )
468- fun testDexLiquidityConstraints () {
469- safeReset ()
470-
471- // USDF liquidity provider
472- let lpUser = Test .createAccount ()
473- transferTokensWithSetup (tokenIdentifier : MAINNET_USDF_TOKEN_ID , from : MAINNET_USDF_HOLDER , to : lpUser , amount : 5000.0 )
474- createPosition (admin : MAINNET_PROTOCOL_ACCOUNT , signer : lpUser , amount : 5000.0 , vaultStoragePath : MAINNET_USDF_STORAGE_PATH , pushToDrawDownSink : false )
475-
476- // Borrower: 200 FLOW @ $1.00 (CF=0.80), borrow 130 USDF
477- // health = 200*1.0*0.80 / 130 = 160/130 ≈ 1.2308 (healthy)
478- let user = Test .createAccount ()
479- var res = setupGenericVault (user , vaultIdentifier : MAINNET_USDF_TOKEN_ID )
480- Test .expect (res , Test .beSucceeded ())
481- transferFlowTokens (to : user , amount : 200.0 )
482- createPosition (admin : MAINNET_PROTOCOL_ACCOUNT , signer : user , amount : 200.0 , vaultStoragePath : FLOW_VAULT_STORAGE_PATH , pushToDrawDownSink : false )
483- let pid = getLastPositionId ()
484- borrowFromPosition (signer : user , positionId : pid ,
485- tokenTypeIdentifier : MAINNET_USDF_TOKEN_ID , vaultStoragePath : MAINNET_USDF_STORAGE_PATH ,
486- amount : 130.0 , beFailed : false )
487-
488- let initialHealth = getPositionHealth (pid : pid , beFailed : false )
489- Test .assert (initialHealth > 1.0 , message : " Position should start healthy" )
490-
491- // FLOW crash: $1.00 -> $0.75; health = 120/130 ≈ 0.9231 (unhealthy)
492- setMockOraclePrice (signer : MAINNET_PROTOCOL_ACCOUNT , forTokenIdentifier : MAINNET_FLOW_TOKEN_ID , price : 0.75 )
493- let crashedHealth = getPositionHealth (pid : pid , beFailed : false )
494- Test .assert (crashedHealth < 1.0 , message : " Position must be unhealthy after FLOW crash" )
495-
496- // Configure MockDexSwapper for FLOW -> USDF at price ratio 0.75.
497- // DEX vault 23 USDF — 50% of the 46 required for repayment.
498- transferTokensWithSetup (tokenIdentifier : MAINNET_USDF_TOKEN_ID , from : MAINNET_USDF_HOLDER , to : MAINNET_PROTOCOL_ACCOUNT , amount : 23.0 )
499- setMockDexPriceForPair (
500- signer : MAINNET_PROTOCOL_ACCOUNT ,
501- inVaultIdentifier : MAINNET_FLOW_TOKEN_ID ,
502- outVaultIdentifier : MAINNET_USDF_TOKEN_ID ,
503- vaultSourceStoragePath : MAINNET_USDF_STORAGE_PATH ,
504- priceRatio : 0.75
505- )
506-
507- // Scenario 1: DEX has only 23 USDF, needs 46 — liquidation must revert atomically
508- let failRes = liquidateViaMockDex (
509- signer : MAINNET_PROTOCOL_ACCOUNT ,
510- pid : pid ,
511- debtVaultIdentifier : MAINNET_USDF_TOKEN_ID ,
512- seizeVaultIdentifier : MAINNET_FLOW_TOKEN_ID ,
513- seizeAmount : 55.0 ,
514- repayAmount : 46.0 ,
515- )
516- Test .expect (failRes , Test .beFailed ())
517-
518- let healthAfterFail = getPositionHealth (pid : pid , beFailed : false )
519- Test .assert (healthAfterFail < 1.0 , message : " Position must remain unhealthy after failed DEX liquidation" )
520-
521- let detailsAfterFail = getPositionDetails (pid : pid , beFailed : false )
522- Test .assertEqual (200.0 , getCreditBalanceForType (details : detailsAfterFail , vaultType : CompositeType (MAINNET_FLOW_TOKEN_ID )! ))
523- Test .assertEqual (130.0 , getDebitBalanceForType (details : detailsAfterFail , vaultType : CompositeType (MAINNET_USDF_TOKEN_ID )! ))
524-
525- // Scenario 2: top up DEX vault (+30 USDF, total 53 >= 46) — liquidation succeeds
526- transferFungibleTokens (tokenIdentifier : MAINNET_USDF_TOKEN_ID , from : MAINNET_USDF_HOLDER , to : MAINNET_PROTOCOL_ACCOUNT , amount : 30.0 )
527-
528- let successRes = liquidateViaMockDex (
529- signer : MAINNET_PROTOCOL_ACCOUNT ,
530- pid : pid ,
531- debtVaultIdentifier : MAINNET_USDF_TOKEN_ID ,
532- seizeVaultIdentifier : MAINNET_FLOW_TOKEN_ID ,
533- seizeAmount : 55.0 ,
534- repayAmount : 46.0 ,
535- )
536- Test .expect (successRes , Test .beSucceeded ())
537-
538- // post-health = (200-55)*0.75*0.80 / (130-46) = 87/84 ≈ 1.036 (within 1.05 target)
539- let postHealth = getPositionHealth (pid : pid , beFailed : false )
540- Test .assert (postHealth > 1.0 && postHealth < = 1.05 , message : " Position must be healthy after liquidation and not exceed liquidationTargetHF (1.05)" )
541- Test .assert (postHealth > crashedHealth )
542-
543- // Verify seizure: 55 FLOW seized, 46 USDF repaid
544- let detailsAfterLiq = getPositionDetails (pid : pid , beFailed : false )
545- Test .assertEqual (145.0 , getCreditBalanceForType (details : detailsAfterLiq , vaultType : CompositeType (MAINNET_FLOW_TOKEN_ID )! )) // 200 - 55 = 145
546- Test .assertEqual (84.0 , getDebitBalanceForType (details : detailsAfterLiq , vaultType : CompositeType (MAINNET_USDF_TOKEN_ID )! )) // 130 - 46 = 84
547- }
467+ // access(all) fun testDexLiquidityConstraints()
468+ //
469+ // TODO: DEX Liquidity Constraints test should be implemented once automated liquidation
470+ // is in place. The relevant scenario is: a DEX vault is underfunded relative to the
471+ // debt repayment required, causing an automated liquidation to fail atomically, after
472+ // which topping up the DEX vault allows the same liquidation to succeed. This can only
473+ // be meaningfully tested when FlowALP itself invokes the DEX as part of its liquidation
474+ // code path, rather than the caller supplying pre-swapped funds via manualLiquidation.
548475
549476// =============================================================================
550477// Stability and Insurance Fee Accrual — fees not collected for liquidated funds
0 commit comments