FCM Architecture Overview
This document explains how Flow Credit Market's (FCM) three core components - Automated Lending Platform (ALP), Flow Yield Vaults (FYV), and Medium Of Exchange Token (MOET) - integrate to create a complete yield-generating system with automated liquidation prevention.
FCM's architecture is designed for composability and automation. Each component has clear responsibilities and communicates through standardized interfaces (DeFi Actions), enabling:
- Independent development and upgrades
- Third-party strategy integrations
- System resilience through modularity
High-Level Architecture
_46graph TB_46 subgraph "User Interface"_46 User[User/dApp]_46 end_46_46 subgraph "FCM System"_46 subgraph "ALP - Lending Layer"_46 Pool[Pool Contract]_46 Position[Position]_46 Oracle[Price Oracle]_46 end_46_46 subgraph "FYV - Yield Layer"_46 Strategy[Yield Strategy]_46 AutoBalancer[Auto Balancer]_46 Swapper[Token Swapper]_46 end_46_46 subgraph "MOET - Currency Layer"_46 MOET[MOET Token]_46 Pricing[Price Feeds]_46 end_46 end_46_46 subgraph "External Protocols"_46 DEX[DEXes/AMMs]_46 Farm[Yield Farms]_46 LP[Liquidity Pools]_46 end_46_46 User -->|Deposit Collateral| Position_46 Position -->|Auto-borrow| MOET_46 MOET -->|Via DrawDownSink| Strategy_46 Strategy -->|Deploy| DEX_46 Strategy -->|Deploy| Farm_46 Strategy -->|Deploy| LP_46_46 Oracle -->|MOET-denominated prices| Pool_46 Pricing -->|Price data| Oracle_46_46 AutoBalancer -->|Manage exposure| Strategy_46 Strategy -->|Via TopUpSource| Position_46_46 style ALP fill:#f9f,stroke:#333,stroke-width:3px_46 style FYV fill:#bfb,stroke:#333,stroke-width:3px_46 style MOET fill:#fbb,stroke:#333,stroke-width:3px
Component Integration
1. ALP ↔ MOET Integration
Purpose: MOET serves as the unit of account and primary borrowed asset for ALP.
Integration points:
_10ALP Pool_10├── defaultToken: Type<@MOET.Vault>_10├── priceOracle: Returns prices in MOET terms_10├── Auto-borrowing: Borrows MOET_10└── Debt tracking: Denominated in MOET
Key interactions:
-
Price Quotation: All token prices quoted in MOET
_10FLOW/MOET: 1.0_10USDC/MOET: 1.0_10stFLOW/MOET: 1.05 -
Health Calculations: All in MOET terms
_10Effective Collateral = FLOW amount × FLOW/MOET price × collateral factor_10Effective Debt = MOET borrowed_10Health Factor = Effective Collateral / Effective Debt -
Auto-Borrowing: Always borrows MOET
_10User deposits → ALP calculates capacity → Borrows MOET → User receives MOET
2. ALP ↔ FYV Integration
Purpose: FYV receives borrowed funds from ALP and provides liquidity for liquidation prevention.
Integration via DeFi Actions:
_10ALP Position_10├── DrawDownSink → FYV Strategy (when overcollateralized)_10└── TopUpSource ← FYV Strategy (when undercollateralized)
Interaction flow:
Overcollateralized (HF > 1.5)
_13Position detects: HF = 1.8 (too high)_13↓_13Position calculates: Can borrow $200 more MOET_13↓_13Position borrows: 200 MOET from Pool_13↓_13Position pushes: 200 MOET → DrawDownSink_13↓_13DrawDownSink = FYV Strategy_13↓_13FYV Strategy swaps: 200 MOET → 200 YieldToken_13↓_13AutoBalancer holds: YieldToken, generates yield
Undercollateralized (HF < 1.1)
_13Position detects: HF = 1.05 (too low)_13↓_13Position calculates: Need to repay $150 MOET_13↓_13Position pulls: Request 150 MOET from TopUpSource_13↓_13TopUpSource = FYV Strategy_13↓_13FYV Strategy swaps: 150 YieldToken → 150 MOET_13↓_13Position repays: 150 MOET to Pool_13↓_13New HF: 1.3 (restored to target)
Code integration:
The integration is implemented through DeFi Actions interfaces in Cadence. On the ALP side, each Position holds references to a DrawDownSink and TopUpSource, which are called during rebalancing operations. When the position becomes overcollateralized, it borrows additional funds and pushes them to the DrawDownSink. When undercollateralized, it pulls funds from the TopUpSource to repay debt.
_17// ALP side (simplified)_17access(all) struct Position {_17 access(self) var drawDownSink: {DeFiActions.Sink}?_17 access(self) var topUpSource: {DeFiActions.Source}?_17_17 // When overcollateralized_17 fun rebalanceDown() {_17 let borrowed <- pool.borrow(amount: excessCapacity)_17 self.drawDownSink?.deposit(vault: <-borrowed)_17 }_17_17 // When undercollateralized_17 fun rebalanceUp() {_17 let repayment <- self.topUpSource?.withdraw(amount: shortfall)_17 pool.repay(vault: <-repayment)_17 }_17}
On the FYV side, strategies implement the DeFi Actions interfaces by providing Sink and Source creation functions. These functions return objects that handle the swap between MOET and yield-bearing tokens. When ALP calls the Sink, FYV converts MOET into yield tokens. When ALP pulls from the Source, FYV converts yield tokens back to MOET.
TracerStrategy is one of FYV's yield strategies that tracks and manages positions in external yield-generating protocols. It acts as the bridge between ALP's lending system and external DeFi opportunities, automatically converting between MOET and yield tokens while maintaining the optimal balance for returns.
_11// FYV side (simplified)_11access(all) struct TracerStrategy {_11 // Implements DeFi Actions interfaces_11 access(all) fun createSink(): {DeFiActions.Sink} {_11 // Returns sink that swaps MOET → YieldToken_11 }_11_11 access(all) fun createSource(): {DeFiActions.Source} {_11 // Returns source that swaps YieldToken → MOET_11 }_11}
3. FYV ↔ MOET Integration
Purpose: MOET is the medium of exchange between FYV and external yield sources.
Flow:
_10FYV receives MOET → Swaps to target token → Deploys to yield source_10↓_10Time passes, yield accumulates_10↓_10When needed: Exit yield source → Swap to MOET → Return to ALP
Example with TracerStrategy:
_161. Receive MOET from ALP_16 ├── DrawDownSink.deposit(moetVault)_16_162. Swap MOET → YieldToken_16 ├── Swapper.swap(moet → yieldToken)_16 └── AutoBalancer.hold(yieldToken)_16_163. Generate yield_16 ├── YieldToken appreciates_16 ├── Farming rewards accrue_16 └── Trading fees accumulate_16_164. Provide back to ALP (when needed)_16 ├── AutoBalancer.release(yieldToken)_16 ├── Swapper.swap(yieldToken → moet)_16 └── TopUpSource.withdraw() returns MOET
Data Flow Architecture
User Deposit Flow
_28sequenceDiagram_28 participant User_28 participant Position_28 participant Pool_28 participant Oracle_28 participant DrawDownSink_28 participant FYV_28_28 User->>Position: deposit(collateral)_28 Position->>Position: Store collateral_28 Position->>Pool: Update collateral balance_28 Pool->>Pool: updateScaledBalance()_28_28 Position->>Oracle: getPrice(collateralToken)_28 Oracle-->>Position: priceInMOET_28_28 Position->>Position: calculateHealth()_28 Note over Position: Check if auto-borrow enabled_28 alt HF > maxHealth AND auto-borrow enabled_28 Position->>Position: Calculate excess capacity_28 Position->>Pool: borrow(excessCapacity)_28 Pool-->>Position: MOET vault_28 Position->>DrawDownSink: deposit(MOET)_28 DrawDownSink->>FYV: Swap MOET to yield tokens_28 FYV->>FYV: Deploy to strategy_28 end_28_28 Position-->>User: success
Price Change & Rebalancing Flow
_34sequenceDiagram_34 participant Oracle_34 participant Position_34 participant Pool_34 participant TopUpSource_34 participant FYV_34_34 Oracle->>Oracle: Price update (collateral drops)_34_34 Note over Position: Periodic check or triggered_34_34 Position->>Oracle: getPrice(collateralToken)_34 Oracle-->>Position: newPrice (lower)_34_34 Position->>Pool: getCurrentDebt()_34 Pool-->>Position: currentDebt_34_34 Position->>Position: calculateHealth()_34 Note over Position: HF < minHealth (e.g., 1.1)_34_34 Position->>Position: Calculate required repayment_34 Note over Position: Need to reach target HF (1.3)_34_34 Position->>TopUpSource: withdraw(repaymentAmount)_34 TopUpSource->>FYV: Request MOET_34 FYV->>FYV: Swap YieldToken → MOET_34 FYV-->>TopUpSource: MOET vault_34 TopUpSource-->>Position: MOET vault_34_34 Position->>Pool: repay(MOET)_34 Pool->>Pool: updateDebt(-amount)_34_34 Position->>Position: calculateHealth()_34 Note over Position: HF restored to 1.3
Component Responsibilities
ALP Responsibilities
| Function | Description |
|---|---|
| Position Management | Create, track, and manage user positions |
| Collateral Tracking | Monitor deposited collateral using scaled balances |
| Debt Tracking | Track borrowed amounts with interest accrual |
| Health Monitoring | Calculate and monitor position health factors |
| Auto-Borrowing | Automatically borrow MOET when overcollateralized |
| Auto-Repayment | Automatically repay when undercollateralized |
| Liquidation | Handle traditional liquidations if auto-repayment fails |
| Interest Calculation | Accrue interest on borrowed amounts |
| Oracle Integration | Query prices for health calculations |
FYV Responsibilities
| Function | Description |
|---|---|
| Strategy Management | Implement and manage yield strategies |
| Capital Deployment | Deploy received MOET to yield sources |
| Yield Generation | Generate returns through various mechanisms |
| Token Swapping | Swap between MOET and yield tokens |
| Auto-Balancing | Maintain optimal exposure to yield tokens |
| Liquidity Provision | Provide MOET when ALP needs rebalancing |
| Risk Management | Monitor and adjust strategy parameters |
| Yield Compounding | Reinvest returns for compound growth |
MOET Responsibilities
| Function | Description |
|---|---|
| Unit of Account | Provide standardized pricing unit |
| Value Transfer | Enable value flow between ALP and FYV |
| Price Stability | Maintain stable value (if stablecoin) |
| Oracle Integration | Provide price feeds for all assets |
| Liquidity | Ensure deep liquidity for swaps |
Communication Patterns
1. DeFi Actions Pattern (ALP ↔ FYV)
DeFi Actions enables ALP and FYV to communicate through standardized interfaces without tight coupling. The Sink pattern allows ALP to push borrowed funds to FYV strategies, while the Source pattern enables ALP to pull funds back when needed for rebalancing or repayment.
Sink Pattern (Push):
When ALP has excess borrowing capacity or newly borrowed funds, it uses the Sink interface to deposit MOET into FYV strategies. The FYV strategy receives the funds and automatically converts them to yield-bearing tokens.
_10// ALP pushes to FYV_10access(all) resource interface Sink {_10 access(all) fun deposit(vault: @{FungibleToken.Vault})_10}_10_10// Usage_10let sink = fyvStrategy.createSink()_10sink.deposit(vault: <-moetVault)
Source Pattern (Pull):
When ALP needs funds to maintain position health, it pulls from the Source interface. FYV converts yield tokens back to MOET and provides the requested amount, enabling automatic liquidation prevention.
_10// ALP pulls from FYV_10access(all) resource interface Source {_10 access(all) fun withdraw(amount: UFix64, type: Type): @{FungibleToken.Vault}_10}_10_10// Usage_10let source = fyvStrategy.createSource()_10let moet <- source.withdraw(amount: 100.0, type: Type<@MOET.Vault>())
2. Oracle Pattern (ALP ↔ MOET)
The Oracle pattern provides a standardized way for ALP to query token prices in MOET terms. All collateral and debt calculations use these MOET-denominated prices, ensuring consistency across the system. This enables health factor calculations and determines borrowing capacity based on real-time market data.
Price Query:
The PriceOracle interface returns the current price of any token type denominated in MOET. For example, querying the price of FLOW returns how many MOET one FLOW is worth, which ALP uses to calculate effective collateral values.
_10// ALP queries prices in MOET terms_10access(all) resource interface PriceOracle {_10 access(all) fun getPrice(token: Type): UFix64_10}_10_10// Usage_10let flowPrice = oracle.getPrice(Type<@FlowToken.Vault>())_10// Returns: 1.0 (1 FLOW = 1 MOET)
3. Event-Driven Pattern
FCM components communicate state changes through events, enabling monitoring, analytics, and external integrations. Each component emits events for significant actions like position changes, yield generation, and token operations. These events allow off-chain systems to track user activity, trigger notifications, and maintain historical records without polling smart contracts.
Key events across components:
ALP emits events for all position lifecycle operations including creation, borrowing, repayment, and rebalancing. FYV broadcasts events when deploying to strategies, generating yield, or providing liquidity back to ALP. MOET tracks token supply changes through mint and burn events, ensuring transparency in the stablecoin's circulation.
_14// ALP events_14access(all) event PositionCreated(pid: UInt64, owner: Address)_14access(all) event Borrowed(pid: UInt64, amount: UFix64)_14access(all) event Repaid(pid: UInt64, amount: UFix64)_14access(all) event Rebalanced(pid: UInt64, newHealth: UFix64)_14_14// FYV events_14access(all) event StrategyDeployed(amount: UFix64, strategy: String)_14access(all) event YieldGenerated(amount: UFix64)_14access(all) event LiquidityProvided(amount: UFix64, toALP: Bool)_14_14// MOET events_14access(all) event TokensMinted(amount: UFix64, recipient: Address)_14access(all) event TokensBurned(amount: UFix64)
System States
Normal Operation State
_11System State: Healthy_11├── ALP Positions: All HF between 1.1 and 1.5_11├── FYV Strategies: Generating yield normally_11├── MOET: Stable and liquid_11└── Oracles: Providing fresh prices_11_11Actions:_11- Accept new deposits_11- Allow withdrawals_11- Process rebalancing_11- Generate yield
Stress State (Price Volatility)
_11System State: Under Stress_11├── ALP Positions: Some HF approaching 1.1_11├── FYV Strategies: May need to provide liquidity_11├── MOET: May see increased trading volume_11└── Oracles: Prices updating frequently_11_11Actions:_11- Trigger frequent rebalancing_11- FYV provides liquidity to ALP_11- Some yield positions exited_11- Increased monitoring
Emergency State
_11System State: Emergency_11├── ALP Positions: Multiple HF < 1.0_11├── FYV Strategies: Emergency liquidation mode_11├── MOET: Potential depeg risk_11└── Oracles: Stale or unreliable_11_11Actions:_11- Circuit breakers activated_11- Liquidations triggered_11- Deposits paused_11- Admin intervention required
Scalability & Performance
Optimizations
Scaled Balance System - ALP uses a scaled balance approach that avoids updating every position when interest accrues. Instead, a single interest index update affects all positions simultaneously, making the system gas-efficient even with thousands of active positions.
Batch Rebalancing - The protocol allows multiple positions to be rebalanced in a single transaction, enabling keepers to optimize gas costs by processing several positions at once rather than submitting individual transactions for each rebalancing operation.
Lazy Evaluation - All components use lazy evaluation patterns where prices are only fetched when needed, health factors are calculated only when accessed, and interest accrues only when a position is touched. This approach minimizes unnecessary computations and reduces gas costs for operations that don't require the latest state.
Event-Driven Updates - The system emits events for all critical operations, allowing off-chain indexers to track state changes efficiently. This enables UI updates without constant blockchain queries and significantly reduces RPC load on the network while providing users with real-time information.
Limits & Constraints
| Component | Limit | Reason |
|---|---|---|
| ALP Max Positions | Configurable | Gas limits for iteration |
| FYV Strategies per Vault | ~10-20 | Complexity management |
| Rebalancing Frequency | ~1 per block | Gas and Oracle freshness |
| Max Leverage | ~5x | Safety (1.0 HF = 100%, 1.1-1.5 range) |
Security Architecture
Defense in Depth
Layer 1: Input Validation
- All user inputs sanitized
- Type checking enforced
- Capability-based access control
Layer 2: Business Logic
- Health factor checks before operations
- Minimum/maximum limits enforced
- Oracle staleness checks
Layer 3: Circuit Breakers
- Emergency pause functionality
- Liquidation warm-up periods
- Admin override capabilities
Layer 4: Economic Security
- Over-collateralization requirements
- Liquidation incentives
- Oracle price deviation limits
Layer 5: Monitoring
- Event emission for all critical operations
- Off-chain monitoring systems
- Automated alerts
Next Steps
- Understand the math: Mathematical Foundations
- Explore ALP details: ALP Architecture
- Learn about FYV: FYV Documentation
- Deep dive into MOET: MOET Documentation