Conversation
…dation - fork_multiple_positions_per_user.cdc covering three scenarios: - Multiple positions with distinct collateral types (FLOW, USDF, USDC, WETH, WBTC) and isolation guarantees between them - Cross-position effects through shared liquidity pools - Batch liquidation of 4 positions (2 full, 2 partial) in a single tx
…eates 100 positions across three collateral types (50 USDF, 45 USDC, 5 WBTC), crashes all collateral prices 40% simultaneously, and batch-liquidates all positions via MockDexSwapper in chunks of 10 to stay within computation limits.
…ion-per-user-scenarios-testing # Conflicts: # flow.json
cadence/tests/transactions/flow-alp/pool-management/batch_liquidate_via_mock_dex.cdc
Show resolved
Hide resolved
Co-authored-by: patrick <72362902+holyfuchs@users.noreply.github.com>
…on flow.json hash
cadence/tests/transactions/flow-alp/pool-management/batch_manual_liquidation.cdc
Show resolved
Hide resolved
…testing # Conflicts: # cadence/tests/test_helpers.cdc # flow.json
| /// repayAmounts: Array of repay amounts for each position | ||
| transaction( | ||
| pids: [UInt64], | ||
| debtVaultIdentifier: String, |
There was a problem hiding this comment.
change debt* to repayment* to reduce confusion as it represents a repayment, not actual the actual debt
| // Deposit seized collateral back to liquidator | ||
| // For simplicity, we'll just destroy it in this test transaction | ||
| // In production, you'd want to properly handle the seized collateral | ||
| destroy seizedVault |
There was a problem hiding this comment.
depositing it back to liquidator would improve testing, as it'd be possible to check the vault balance after liquidation
| /// repayAmounts: Array of debt amounts to repay for each position (sourced from the DEX) | ||
| transaction( | ||
| pids: [UInt64], | ||
| debtVaultIdentifier: String, |
There was a problem hiding this comment.
change debt* to repayment*
| ) | ||
|
|
||
| totalRepaid = totalRepaid + repayAmount | ||
| destroy seizedVault |
There was a problem hiding this comment.
deposit back to liquidator to improve test assertions
There was a problem hiding this comment.
yeah, better not to destroy, just finish up by depositing somewhere ideally.
|
|
||
| // Build an exact quote for the repayAmount we need from the swapper's vaultSource | ||
| let swapQuote = MockDexSwapper.BasicQuote( | ||
| inType: seizeType, |
There was a problem hiding this comment.
nit: it's slightly awkward to swap seizeType to debtType in order to get back seizeType back from liquidator. It would be better to use something like FlowToken or another token to clearly demonstrate that the debt could be repaid with any other token, not just debtType
| // pid 1: 0.06 WETH @ $3500 (CF=0.75), borrow 90 → health = 0.06*3500*0.75/90 = 1.750 | ||
| // pid 2: 80 USDC @ $1.00 (CF=0.85), borrow 40 → health = 80*1.0*0.85/40 = 1.700 | ||
| // pid 3: 0.0004 WBTC @ $50000 (CF=0.75), borrow 10 → health = 0.0004*50000*0.75/10 = 1.500 | ||
| // pid 4: 200 FLOW @ $1.00 (CF=0.80), borrow 80 → health = 200*1.0*0.80/80 = 2.000 |
There was a problem hiding this comment.
technically this will be collateral withdrawal, not borrowing
put FLOW, get FLOW back
| // 40% simultaneously, requiring a chunked batch DEX liquidation of every position. | ||
| // | ||
| // ============================================================================= | ||
| access(all) fun testMassUnhealthyLiquidations() { |
There was a problem hiding this comment.
would it be possible to store the ranges in some variables instead of using magic numbers through the test, even with comments it's tricky to track all of them
| @@ -0,0 +1,9 @@ | |||
| import "MockOracle" | |||
There was a problem hiding this comment.
can we name this something else? or move into a scripts folder in the tests section, since this only grabs from the MockOracle.
| debtVaultIdentifier: String, | ||
| seizeVaultIdentifiers: [String], | ||
| seizeAmounts: [UFix64], | ||
| repayAmounts: [UFix64] |
There was a problem hiding this comment.
not needed for this PR, but i do wonder if this should be a single array of a.composite data structure or even map, rather than 4 separate arrays, since this adds 3 asserts, and slightly more complex for loop notion. for idx in InclusiveRange(0, numPositions - 1) {
mostly a nit though, so up to you if it's easy to adjust in this PR, or to just keep in mind for the future
| ) | ||
|
|
||
| totalRepaid = totalRepaid + repayAmount | ||
| destroy seizedVault |
There was a problem hiding this comment.
yeah, better not to destroy, just finish up by depositing somewhere ideally.
| depositCapacityCap: 1_000_000.0 | ||
| ) | ||
|
|
||
| addSupportedTokenZeroRateCurve( |
There was a problem hiding this comment.
Dete actually has mentioned that he's aiming to NOT allow other stables as collateral in the protocol. I think if we do want to keep one stable, it's probably okay, but we def don't need 2 i think. If it's easy to remove, let's just do 1 stable coin only.
| // pid 1: 0.06 WETH @ $3500 (CF=0.75), borrow 90 → health = 0.06*3500*0.75/90 = 1.750 | ||
| // pid 2: 80 USDC @ $1.00 (CF=0.85), borrow 40 → health = 80*1.0*0.85/40 = 1.700 | ||
| // pid 3: 0.0004 WBTC @ $50000 (CF=0.75), borrow 10 → health = 0.0004*50000*0.75/10 = 1.500 | ||
| // pid 4: 200 FLOW @ $1.00 (CF=0.80), borrow 80 → health = 200*1.0*0.80/80 = 2.000 |
| inVaultIdentifier: MAINNET_USDF_TOKEN_ID, | ||
| outVaultIdentifier: MAINNET_FLOW_TOKEN_ID, | ||
| vaultSourceStoragePath: FLOW_VAULT_STORAGE_PATH, | ||
| priceRatio: 0.3 // $0.30 USDF / $1.00 FLOW |
There was a problem hiding this comment.
nit: $1.00 FLOW is a token count right? let's remove the $ if so
| // and 1 unit of each collateral token to initialize vault storage paths. | ||
| // | ||
| // Repay amounts derived from: repay = debt - (collat - seize) * CF * P_crashed / H_target | ||
| // WETH=71: debt=90, (0.06-0.035)*0.75*1050 = 19.6875, H≈1.034 → 90 - 19.6875/1.034 ≈ 71 |
There was a problem hiding this comment.
You mention it a bit below but might be good to mention where 1.034 comes from
Closes: #147
Multi-Position Per User Scenarios: Fork Tests & Supporting Infrastructure
cadence/tests/fork_multiple_positions_per_user.cdcRuns against mainnet at block 142528994 using real token holders and real token identifiers (FLOW, USDF, USDC, WETH, WBTC). Contains 4 tests:
testMultiplePositionsPerUser — Creates 5 positions with different collateral types, borrows varying amounts from each, and asserts that operations on one position do not affect the health factors of others (isolation guarantee).
testPositionInteractionsSharedLiquidity — Verifies cross-position effects through the shared FLOW liquidity pool: Position A's heavy borrowing reduces available liquidity for Position B, a subsequent repayment restores it, and a crash of Position A's collateral price has zero effect on Position B's health.
testBatchLiquidations — Creates 5 positions (USDF, WETH, USDC, WBTC, FLOW) with differentiated borrow levels, crashes 4 collateral prices, then executes a single-transaction batch liquidation: 2 full liquidations (WETH, USDF) and 2 partial liquidations (USDC, WBTC). The FLOW-collateral position, whose price is unchanged, remains untouched.
testMassUnhealthyLiquidations — System-wide stress test: 100 positions across 3 collateral types (50 USDF × 10 USDF, 45 USDC × 2 USDC, 5 WBTC × 0.00009 WBTC), two risk tiers (high/moderate) per stablecoin group, simultaneous 40% price crash across all three collateral types, then batch DEX liquidation of all 100 positions in chunks of 10 to stay within computation limits. Verifies all positions recover health and protocol FLOW reserve stays positive.
cadence/transactions/flow-alp/pool-management/batch_manual_liquidation.cdc— Liquidates multiple positions in one transaction using the caller's own debt tokens as repayment.cadence/transactions/flow-alp/pool-management/batch_liquidate_via_mock_dex.cdc— Liquidates multiple positions in one transaction sourcing repayment from a pre-configured MockDexSwapper.