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


_47
graph TB
_47
subgraph "User Interface"
_47
User[User/dApp]
_47
end
_47
_47
subgraph "FCM System"
_47
subgraph ALP["ALP Components"]
_47
Pool[Pool Contract]
_47
Position[Position]
_47
Oracle[Price Oracle]
_47
end
_47
_47
subgraph FYV["FYV Components"]
_47
Strategy[Yield Strategy]
_47
AutoBalancer[Auto Balancer]
_47
Swapper[Token Swapper]
_47
end
_47
_47
subgraph MOET_Layer["MOET Layer"]
_47
MOET[MOET Token]
_47
Pricing[Price Feeds]
_47
end
_47
end
_47
_47
subgraph "External Protocols"
_47
DEX[DEXes/AMMs]
_47
Farm[Yield Farms]
_47
LP[Liquidity Pools]
_47
end
_47
_47
User -->|Deposit Collateral| Position
_47
Position -->|Auto-borrow| MOET
_47
MOET -->|Via DrawDownSink| Strategy
_47
Strategy -->|Deploy| DEX
_47
Strategy -->|Deploy| Farm
_47
Strategy -->|Deploy| LP
_47
_47
Oracle -->|MOET-denominated prices| Pool
_47
Pricing -->|Price data| Oracle
_47
_47
AutoBalancer -->|Manage exposure| Strategy
_47
Strategy -->|Via TopUpSource| Position
_47
_47
style ALP fill:#4a7abf,stroke:#333,stroke-width:2px,color:#fff
_47
style FYV fill:#4d994d,stroke:#333,stroke-width:2px,color:#fff
_47
style MOET_Layer fill:#d94d4d,stroke:#333,stroke-width:2px,color:#fff
_47
style MOET fill:#d94d4d,stroke:#333,stroke-width:2px,color:#fff

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


_14
graph LR
_14
User[👤 You deposit<br/>1000 FLOW] --> Position[ALP Position<br/>stores collateral]
_14
Position --> Oracle[Oracle checks<br/>FLOW price]
_14
Oracle --> Health{Health Factor<br/>calculation}
_14
Health -->|HF > 1.5<br/>Can borrow| Borrow[Auto-borrow<br/>615 MOET]
_14
Health -->|HF ≤ 1.5<br/>No borrowing| Done1[✅ Deposit complete]
_14
Borrow --> DrawDown[Push to<br/>DrawDownSink]
_14
DrawDown --> FYV[FYV Strategy<br/>swaps to yield tokens]
_14
FYV --> Done2[✅ Earning yield<br/>HF = 1.3]
_14
_14
style Position fill:#4a7abf,stroke:#333,stroke-width:2px,color:#fff
_14
style FYV fill:#4d994d,stroke:#333,stroke-width:2px,color:#fff
_14
style Borrow fill:#d94d4d,stroke:#333,stroke-width:2px,color:#fff
_14
style Done2 fill:#4d994d,stroke:#333,stroke-width:2px,color:#fff

Price Drop & Rebalancing Flow


_13
graph LR
_13
Drop[📉 FLOW price<br/>drops 20%] --> Position[ALP Position<br/>detects HF = 1.05]
_13
Position --> Calc[Calculate needed<br/>repayment: 123 MOET]
_13
Calc --> TopUp[Pull from<br/>TopUpSource]
_13
TopUp --> FYV[FYV Strategy<br/>swaps yield tokens]
_13
FYV --> MOET[Returns<br/>123 MOET]
_13
MOET --> Repay[ALP repays<br/>debt to Pool]
_13
Repay --> Restored[✅ Health restored<br/>HF = 1.3]
_13
_13
style Position fill:#4a7abf,stroke:#333,stroke-width:2px,color:#fff
_13
style FYV fill:#4d994d,stroke:#333,stroke-width:2px,color:#fff
_13
style MOET fill:#d94d4d,stroke:#333,stroke-width:2px,color:#fff
_13
style Restored fill:#4d994d,stroke:#333,stroke-width:2px,color:#fff

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