LLM Notice: This documentation site supports content negotiation for AI agents. Request any page with Accept: text/markdown or Accept: text/plain header to receive Markdown instead of HTML. Alternatively, append ?format=md to any URL. All markdown files are available at /md/ prefix paths. For all content in one file, visit /llms-full.txt
Skip to main content

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.

Key Insight

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


_46
graph 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:


_10
ALP 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:

  1. Price Quotation: All token prices quoted in MOET


    _10
    FLOW/MOET: 1.0
    _10
    USDC/MOET: 1.0
    _10
    stFLOW/MOET: 1.05

  2. Health Calculations: All in MOET terms


    _10
    Effective Collateral = FLOW amount × FLOW/MOET price × collateral factor
    _10
    Effective Debt = MOET borrowed
    _10
    Health Factor = Effective Collateral / Effective Debt

  3. Auto-Borrowing: Always borrows MOET


    _10
    User 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:


_10
ALP Position
_10
├── DrawDownSink → FYV Strategy (when overcollateralized)
_10
└── TopUpSource ← FYV Strategy (when undercollateralized)

Interaction flow:

Overcollateralized (HF > 1.5)


_13
Position detects: HF = 1.8 (too high)
_13
_13
Position calculates: Can borrow $200 more MOET
_13
_13
Position borrows: 200 MOET from Pool
_13
_13
Position pushes: 200 MOET → DrawDownSink
_13
_13
DrawDownSink = FYV Strategy
_13
_13
FYV Strategy swaps: 200 MOET → 200 YieldToken
_13
_13
AutoBalancer holds: YieldToken, generates yield

Undercollateralized (HF < 1.1)


_13
Position detects: HF = 1.05 (too low)
_13
_13
Position calculates: Need to repay $150 MOET
_13
_13
Position pulls: Request 150 MOET from TopUpSource
_13
_13
TopUpSource = FYV Strategy
_13
_13
FYV Strategy swaps: 150 YieldToken → 150 MOET
_13
_13
Position repays: 150 MOET to Pool
_13
_13
New 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)
_17
access(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)
_11
access(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:


_10
FYV receives MOET → Swaps to target token → Deploys to yield source
_10
_10
Time passes, yield accumulates
_10
_10
When needed: Exit yield source → Swap to MOET → Return to ALP

Example with TracerStrategy:


_16
1. Receive MOET from ALP
_16
├── DrawDownSink.deposit(moetVault)
_16
_16
2. Swap MOET → YieldToken
_16
├── Swapper.swap(moet → yieldToken)
_16
└── AutoBalancer.hold(yieldToken)
_16
_16
3. Generate yield
_16
├── YieldToken appreciates
_16
├── Farming rewards accrue
_16
└── Trading fees accumulate
_16
_16
4. 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


_28
sequenceDiagram
_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


_34
sequenceDiagram
_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

FunctionDescription
Position ManagementCreate, track, and manage user positions
Collateral TrackingMonitor deposited collateral using scaled balances
Debt TrackingTrack borrowed amounts with interest accrual
Health MonitoringCalculate and monitor position health factors
Auto-BorrowingAutomatically borrow MOET when overcollateralized
Auto-RepaymentAutomatically repay when undercollateralized
LiquidationHandle traditional liquidations if auto-repayment fails
Interest CalculationAccrue interest on borrowed amounts
Oracle IntegrationQuery prices for health calculations

FYV Responsibilities

FunctionDescription
Strategy ManagementImplement and manage yield strategies
Capital DeploymentDeploy received MOET to yield sources
Yield GenerationGenerate returns through various mechanisms
Token SwappingSwap between MOET and yield tokens
Auto-BalancingMaintain optimal exposure to yield tokens
Liquidity ProvisionProvide MOET when ALP needs rebalancing
Risk ManagementMonitor and adjust strategy parameters
Yield CompoundingReinvest returns for compound growth

MOET Responsibilities

FunctionDescription
Unit of AccountProvide standardized pricing unit
Value TransferEnable value flow between ALP and FYV
Price StabilityMaintain stable value (if stablecoin)
Oracle IntegrationProvide price feeds for all assets
LiquidityEnsure 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
_10
access(all) resource interface Sink {
_10
access(all) fun deposit(vault: @{FungibleToken.Vault})
_10
}
_10
_10
// Usage
_10
let sink = fyvStrategy.createSink()
_10
sink.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
_10
access(all) resource interface Source {
_10
access(all) fun withdraw(amount: UFix64, type: Type): @{FungibleToken.Vault}
_10
}
_10
_10
// Usage
_10
let source = fyvStrategy.createSource()
_10
let 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
_10
access(all) resource interface PriceOracle {
_10
access(all) fun getPrice(token: Type): UFix64
_10
}
_10
_10
// Usage
_10
let 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
_14
access(all) event PositionCreated(pid: UInt64, owner: Address)
_14
access(all) event Borrowed(pid: UInt64, amount: UFix64)
_14
access(all) event Repaid(pid: UInt64, amount: UFix64)
_14
access(all) event Rebalanced(pid: UInt64, newHealth: UFix64)
_14
_14
// FYV events
_14
access(all) event StrategyDeployed(amount: UFix64, strategy: String)
_14
access(all) event YieldGenerated(amount: UFix64)
_14
access(all) event LiquidityProvided(amount: UFix64, toALP: Bool)
_14
_14
// MOET events
_14
access(all) event TokensMinted(amount: UFix64, recipient: Address)
_14
access(all) event TokensBurned(amount: UFix64)

System States

Normal Operation State


_11
System 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
_11
Actions:
_11
- Accept new deposits
_11
- Allow withdrawals
_11
- Process rebalancing
_11
- Generate yield

Stress State (Price Volatility)


_11
System 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
_11
Actions:
_11
- Trigger frequent rebalancing
_11
- FYV provides liquidity to ALP
_11
- Some yield positions exited
_11
- Increased monitoring

Emergency State


_11
System 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
_11
Actions:
_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

ComponentLimitReason
ALP Max PositionsConfigurableGas limits for iteration
FYV Strategies per Vault~10-20Complexity management
Rebalancing Frequency~1 per blockGas and Oracle freshness
Max Leverage~5xSafety (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