Skip to content

[DRAFT] Extract ALP components into separate contracts#160

Draft
jordanschalm wants to merge 12 commits intomainfrom
jord/split-contracts
Draft

[DRAFT] Extract ALP components into separate contracts#160
jordanschalm wants to merge 12 commits intomainfrom
jord/split-contracts

Conversation

@jordanschalm
Copy link
Member

@jordanschalm jordanschalm commented Feb 12, 2026

This PR refactors ALP types and state fields. The PR is not ready for detailed review, but is ready for feedback on the high-level approach.

The goal is to:

Changes

  • Move InterestCurve interface, FixedRateInterestCurve, and KinkInterestCurve from FlowALPv1 into a new standalone FlowALPRateCurves contract
  • Move Pool config/state into a separate contract FlowALPModels
  • Remove where possible thin wrapper functions in FlowALPv1. For example, governance transactions that change config can share a Pool.borrowConfig function, rather than Pool defining setters itself
  • Moved some math functions to FlowALPMath. In this PR we decided to retain the separate Math contract. Given that, I think it makes sense to delegate pure math-related functions into that contract.

Comments

  • Events are currently split between FlowALP and FlowALPModels. (You can only emit an event in the contract in which it is defined.) I think all events should be consolidated in one place. I am thinking of moving all events to FlowALPModels and having access(account) fun emitEvent functions for them.
  • TokenState was moved over to FlowALPModels, but is not interface-typed. May want to apply that pattern to make its fields upgradeable as well.
  • May want to move other models to FlowALPModels
  • Revisit whether EImplementation is useful. If it is, apply and use it consistently.

jordanschalm and others added 6 commits February 12, 2026 10:37
Move InterestCurve interface, FixedRateInterestCurve, and KinkInterestCurve
from FlowALPv1 into a new standalone FlowALPRateCurves contract to improve
modularity and allow rate curve types to be reused independently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rve to FixedCurve, KinkInterestCurve to KinkCurve

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move 9 pool config fields (priceOracle, collateralFactor, borrowFactor,
positionsProcessedPerCallback, liquidationTargetHF, warmupSec,
lastUnpausedAt, dex, dexOracleDeviationBps) into a PoolConfigImpl struct
in a new FlowALPModels contract, centralizing config validation logic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace pure-delegation Pool wrapper functions (setDexOracleDeviationBps,
setDEX) with a single borrowConfig() function that returns a mutable
reference to the pool's PoolConfig. Callers can now invoke config setters
directly. Wrapper functions with events/side effects are preserved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move TokenState struct and EImplementation entitlement to FlowALPModels.
Create PoolStateImpl resource in FlowALPModels to hold Pool's movable
state fields (globalLedger, reserves, insuranceFund, etc.).
Move pure utility functions (perSecondInterestRate, compoundInterestIndex,
dexOraclePriceDeviationInRange) to FlowALPMath, keeping thin wrappers
in FlowALPv1 for backwards compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jordanschalm jordanschalm changed the title [DRAFT] Extract InterestCurve types into FlowALPRateCurves contract [DRAFT] Extract ALP components into separate contracts Feb 13, 2026
jordanschalm and others added 6 commits February 13, 2026 09:38
Pool.state is now typed as @{FlowALPModels.PoolState} instead of the
concrete @FlowALPModels.PoolStateImpl, matching the PoolConfig/PoolConfigImpl
pattern and allowing the implementation to be swapped in future upgrades.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These are configuration fields, not state fields. Moving them to PoolConfig
with getter/setter methods ensures they are upgradeable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All fields on the PoolState interface are now accessed through getter/setter
methods rather than direct field access. This ensures the interface is
upgradeable - fields cannot be changed in interface upgrades, but function
signatures can evolve.

Also fixes a test that relied on dictionary key ordering for position
balances.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These functions interact with pool-level state (reserves, insurance fund)
and are better suited as Pool methods that accept a TokenState reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Base supported token logic on collateralFactor dictionary keys in PoolConfig
rather than globalLedger keys in PoolState. Pool methods now delegate to config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move _borrowOrCreateReserveVault to PoolState as borrowOrCreateReserve
- Move _getSwapperForLiquidation to PoolConfig as getSwapperForLiquidation
- Remove setLiquidationParams, setPauseParams, pausePool wrappers
- Remove setDebugLogging wrapper (callers use borrowConfig() directly)
- Remove unused events: LiquidationParamsUpdated, PauseParamsUpdated, PoolPaused
- Update transactions to use borrowConfig() for pause and debug logging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@@ -1735,22 +999,11 @@ access(all) contract FlowALPv1 {

/// Returns a reference to the reserve vault for the given type, if the token type is supported.
/// If no reserve vault exists yet, and the token type is supported, the reserve vault is created.
access(self) fun _borrowOrCreateReserveVault(type: Type): &{FungibleToken.Vault} {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't move docs over when refactoring

@@ -1996,13 +1249,6 @@ access(all) contract FlowALPv1 {
/// - No swapper is configured for the given token pair (seizeType -> debtType)
///
/// @param seizeType: The collateral token type to swap from
/// @param debtType: The debt token type to swap to
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't move docs

let diffPct: UFix64 = dexPrice < oraclePrice ? diff / dexPrice : diff / oraclePrice
let diffBps = UInt16(diffPct * 10_000.0)
return diffBps <= maxDeviationBps
return FlowALPMath.dexOraclePriceDeviationInRange(dexPrice: dexPrice, oraclePrice: oraclePrice, maxDeviationBps: maxDeviationBps)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix this duplication

@bluesign
Copy link

bluesign commented Feb 14, 2026

I did something similar, MVC pattern ( like https://github.com/jordanschalm/cadence-interface-upgrade-pattern)

I took a different approach ( used attachments basically ) and state code is generated. ( just pushed maybe inspires something: https://github.com/bluesign/upgradeable

Also my old splitting attempt on credit market ( https://github.com/bluesign/fcm-core/tree/master/cadence/contracts ) ( not using the upgradeable but similar ideas )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants