Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 25 additions & 17 deletions cadence/contracts/FlowALPv0.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -101,19 +101,27 @@ access(all) contract FlowALPv0 {
: 0.0 as UFix128
return (deltaDebt * borrowFactor) / withdrawSnap.getPrice()
} else {
// withdrawing reduces collateral
// withdrawing reduces collateral (and may flip into debt beyond zero)
let trueBalance = FlowALPMath.scaledBalanceToTrueBalance(
withdrawBal!.scaledBalance,
interestIndex: withdrawSnap.getCreditIndex()
)
let maxPossible = trueBalance
let requiredCollateral = effectiveDebtTotal * targetHealth
if effectiveCollateralTotal <= requiredCollateral {
return 0.0
}
let deltaCollateralEffective = effectiveCollateralTotal - requiredCollateral
let deltaTokens = (deltaCollateralEffective / collateralFactor) / withdrawSnap.getPrice()
return deltaTokens > maxPossible ? maxPossible : deltaTokens
if deltaTokens <= trueBalance {
// Health target is hit before exhausting credit — collateral-only withdrawal
return deltaTokens
}
// Exhausting all credit still leaves health above target: add debt capacity
let collateralEffectiveValue = (withdrawSnap.getPrice() * trueBalance) * collateralFactor
let remainingCollateral = effectiveCollateralTotal - collateralEffectiveValue
let availableDebtIncrease = (remainingCollateral / targetHealth) - effectiveDebtTotal
let additionalTokens = (availableDebtIncrease * borrowFactor) / withdrawSnap.getPrice()
return trueBalance + additionalTokens
}
}

Expand Down Expand Up @@ -312,7 +320,7 @@ access(all) contract FlowALPv0 {
if let tokenState = self.state.getTokenState(tokenType) {
return tokenState.getInsuranceRate()
}

return nil
}

Expand Down Expand Up @@ -501,7 +509,7 @@ access(all) contract FlowALPv0 {
post {
!self.state.isPositionLocked(pid): "Position is not unlocked"
}

self.lockPosition(pid)

let positionView = self.buildPositionView(pid: pid)
Expand All @@ -521,7 +529,7 @@ access(all) contract FlowALPv0 {
let Pc_oracle = self.config.getPriceOracle().price(ofToken: seizeType)! // collateral price given by oracle ($/C)
// Price of collateral, denominated in debt token, implied by oracle (D/C)
// Oracle says: "1 unit of collateral is worth `Pcd_oracle` units of debt"
let Pcd_oracle = Pc_oracle / Pd_oracle
let Pcd_oracle = Pc_oracle / Pd_oracle

// Compute the health factor which would result if we were to accept this liquidation
let Ce_pre = balanceSheet.effectiveCollateral // effective collateral pre-liquidation
Expand All @@ -532,7 +540,7 @@ access(all) contract FlowALPv0 {
// Ce_seize = effective value of seized collateral ($)
let Ce_seize = FlowALPMath.effectiveCollateral(credit: UFix128(seizeAmount), price: UFix128(Pc_oracle), collateralFactor: Fc)
// De_seize = effective value of repaid debt ($)
let De_seize = FlowALPMath.effectiveDebt(debit: UFix128(repayAmount), price: UFix128(Pd_oracle), borrowFactor: Fd)
let De_seize = FlowALPMath.effectiveDebt(debit: UFix128(repayAmount), price: UFix128(Pd_oracle), borrowFactor: Fd)
let Ce_post = Ce_pre - Ce_seize // position's total effective collateral after liquidation ($)
let De_post = De_pre - De_seize // position's total effective debt after liquidation ($)
let postHealth = FlowALPMath.healthComputation(effectiveCollateral: Ce_post, effectiveDebt: De_post)
Expand All @@ -551,9 +559,9 @@ access(all) contract FlowALPv0 {
message: "DEX/oracle price deviation too large. Dex price: \(Pcd_dex), Oracle price: \(Pcd_oracle)")
// Execute the liquidation
let seizedCollateral <- self._doLiquidation(pid: pid, repayment: <-repayment, debtType: debtType, seizeType: seizeType, seizeAmount: seizeAmount)

self.unlockPosition(pid)

return <- seizedCollateral
}

Expand All @@ -563,7 +571,7 @@ access(all) contract FlowALPv0 {
access(self) fun _doLiquidation(pid: UInt64, repayment: @{FungibleToken.Vault}, debtType: Type, seizeType: Type, seizeAmount: UFix64): @{FungibleToken.Vault} {
pre {
!self.isPausedOrWarmup(): "Liquidations are paused by governance"
// position must have debt and collateral balance
// position must have debt and collateral balance
}

let repayAmount = repayment.balance
Expand Down Expand Up @@ -1670,7 +1678,7 @@ access(all) contract FlowALPv0 {
// Validate constraint: non-zero rate requires swapper
if insuranceRate > 0.0 {
assert(
tsRef.getInsuranceSwapper() != nil,
tsRef.getInsuranceSwapper() != nil,
message:"Cannot set non-zero insurance rate without an insurance swapper configured for \(tokenType.identifier)",
)
}
Expand All @@ -1689,13 +1697,13 @@ access(all) contract FlowALPv0 {
self.isTokenSupported(tokenType: tokenType): "Unsupported token type"
}
let tsRef = self.state.borrowTokenState(tokenType)
?? panic("Invariant: token state missing")
?? panic("Invariant: token state missing")

if let swapper = swapper {
// Validate swapper types match
assert(swapper.inType() == tokenType, message: "Swapper input type must match token type")
assert(swapper.outType() == Type<@MOET.Vault>(), message: "Swapper output type must be MOET")

} else {
// cannot remove swapper if insurance rate > 0
assert(
Expand Down Expand Up @@ -1779,7 +1787,7 @@ access(all) contract FlowALPv0 {
let tsRef = self.state.borrowTokenState(tokenType)
?? panic("Invariant: token state missing")
tsRef.setStabilityFeeRate(stabilityFeeRate)

FlowALPEvents.emitStabilityFeeRateUpdated(
poolUUID: self.uuid,
tokenType: tokenType.identifier,
Expand All @@ -1800,7 +1808,7 @@ access(all) contract FlowALPv0 {
fundRef.balance >= amount,
message: "Insufficient stability fund balance. Available: \(fundRef.balance), requested: \(amount)"
)

let withdrawn <- fundRef.withdraw(amount: amount)
recipient.deposit(from: <-withdrawn)

Expand Down Expand Up @@ -2271,7 +2279,7 @@ access(all) contract FlowALPv0 {
access(self) fun updateInterestRatesAndCollectInsurance(tokenType: Type) {
let tokenState = self._borrowUpdatedTokenState(type: tokenType)
tokenState.updateInterestRates()

// Collect insurance if swapper is configured
// Ensure reserves exist for this token type
if !self.state.hasReserve(tokenType) {
Expand Down Expand Up @@ -2353,7 +2361,7 @@ access(all) contract FlowALPv0 {
access(all) fun getDefaultToken(): Type {
return self.state.getDefaultToken()
}

/// Returns the deposit capacity and deposit capacity cap for a given token type
access(all) fun getDepositCapacityInfo(type: Type): {String: UFix64} {
let tokenState = self._borrowUpdatedTokenState(type: type)
Expand Down
Loading
Loading