1. Morpho Blue Architecture vs Aave/Compound
Morpho Blue represents a fundamental rethinking of DeFi lending. While Aave and Compound pool all liquidity together and set rates algorithmically based on utilization, Morpho Blue creates isolated lending markets with permissionless creation and direct peer-to-peer matching when possible.
The key architectural differences:
| Feature | Aave V3 | Compound V3 | Morpho Blue |
|---|---|---|---|
| Liquidity model | Shared pool | Shared pool | Isolated markets |
| Rate setting | Utilization curve | Utilization curve | Market-specific IRM |
| P2P matching | No | No | Yes (core feature) |
| Market creation | Governance only | Governance only | Permissionless |
| Risk isolation | Partial (E-modes) | Partial | Complete |
| Oracle dependency | Chainlink/custom | Chainlink | Market-defined |
| Governance token | AAVE | COMP | Minimal (MORPHO) |
Morpho Blue's architecture is deliberately minimal. The core protocol has approximately 650 lines of Solidity code, making it easier to audit and reason about than the thousands of lines in Aave's codebase. This minimalism is a feature: complexity is pushed to the market layer (through oracle choice, IRM choice, and LLTV settings) rather than embedded in the core protocol.
Market Identification
Every Morpho Blue market is uniquely identified by a tuple of five parameters:
struct MarketParams {
address loanToken; // What you lend/borrow (e.g., USDC)
address collateralToken; // What secures the loan (e.g., wETH)
address oracle; // Price feed for collateral/loan ratio
address irm; // Interest Rate Model contract
uint256 lltv; // Liquidation Loan-To-Value (e.g., 86%)
}
The market ID is keccak256(abi.encode(marketParams)). This means identical markets cannot be created twice, and agents must query existing markets by their ID hash.
No Central Governance Risk
Because Morpho Blue markets are permissionless, agents can create markets for any token pair with any oracle and IRM. This eliminates governance delays — if USDC/stETH at 90% LLTV doesn't exist, an agent can create it immediately.
2. P2P Matching Mechanics
Morpho Blue's most powerful feature for lending optimization is its peer-to-peer matching engine. Instead of routing all capital through a shared pool (where rate spreads subsidize protocol reserves and bad debt insurance), Morpho directly connects lenders and borrowers when both are present.
How Matching Works
When a borrower requests a loan in a Morpho market:
- Morpho first checks if there are unmatched lender deposits in the same market
- If yes, it matches the borrower directly against the lender at the P2P rate
- The P2P rate is set between the pool supply rate and pool borrow rate
- Both parties get a better rate than the pool: lender earns more, borrower pays less
- Any unmatched portion falls back to the underlying pool (Aave/Compound for Morpho Optimizer, or the Blue pool itself)
Pool supply rate: 4.0% (what Aave pays lenders)
Pool borrow rate: 6.5% (what Aave charges borrowers)
P2P rate: 5.25% (midpoint — both sides benefit)
Lender improvement: +1.25% vs pool
Borrower improvement: -1.25% vs pool
Protocol spread captured: 2.5% → 0% (no intermediary)
Matching Priority Queue
Morpho maintains a FIFO (first-in, first-out) queue for matching. Lenders who deposit earlier get matched first. For agents, this creates a first-mover advantage in high-demand markets — deposit early to get priority matching and earn the superior P2P rate sooner.
Agents should monitor the matching ratio for each market:
matching_monitor.py
async def get_matching_ratio(morpho_contract, market_id: bytes) -> dict:
"""
Returns the fraction of supply that is P2P matched
Higher ratio = better rates for lenders
"""
market_state = await morpho_contract.functions.market(market_id).call()
total_supply_assets = market_state[0] # totalSupplyAssets
total_borrow_assets = market_state[2] # totalBorrowAssets
# P2P matched = min(supply, borrow)
matched = min(total_supply_assets, total_borrow_assets)
supply_match_ratio = matched / total_supply_assets if total_supply_assets > 0 else 0
borrow_match_ratio = matched / total_borrow_assets if total_borrow_assets > 0 else 0
return {
"supply_match_ratio": supply_match_ratio,
"borrow_match_ratio": borrow_match_ratio,
"total_supply": total_supply_assets,
"total_borrow": total_borrow_assets,
"unmatched_supply": total_supply_assets - matched,
}
3. Market Selection Criteria
With thousands of potential Morpho Blue markets, agents need a systematic framework to identify optimal markets for capital deployment. The following criteria help filter from thousands of markets to the best opportunities.
Supply-Side Selection
For agents seeking lending yield, prioritize markets where:
- Matching ratio is high (>60%): Most capital is P2P matched, earning the superior rate
- Utilization is stable (60-80%): Enough demand to ensure matching, not so high that supply exits frequently
- Oracle is battle-tested: Chainlink or Redstone feeds with long track records
- Collateral has deep liquidity: LLTV can be safely maintained; liquidations won't cascade
- LLTV is appropriate: Higher LLTV = higher utilization potential but higher systemic risk
Market Quality Score
market_scorer.py
def score_market(market: dict) -> float:
"""
Score a Morpho Blue market from 0-100 for lending attractiveness.
Higher score = better supply opportunity.
"""
score = 0.0
# Supply APY (0-30 points)
apy = market.get("supply_apy", 0)
score += min(apy * 500, 30) # 6% APY = 30 points
# Matching ratio (0-25 points)
match_ratio = market.get("supply_match_ratio", 0)
score += match_ratio * 25
# Utilization stability (0-20 points)
util = market.get("utilization", 0)
if 0.6 <= util <= 0.8:
score += 20
elif 0.4 <= util < 0.6 or 0.8 < util <= 0.9:
score += 10
# Oracle reliability (0-15 points)
oracle_type = market.get("oracle_type", "unknown")
oracle_scores = {"chainlink": 15, "redstone": 12, "uniswap_twap": 8, "unknown": 0}
score += oracle_scores.get(oracle_type, 0)
# TVL (0-10 points) — prefer established markets
tvl = market.get("tvl_usd", 0)
if tvl > 50_000_000:
score += 10
elif tvl > 10_000_000:
score += 7
elif tvl > 1_000_000:
score += 4
return score
Top Market Categories
Based on historical performance, the highest-quality Morpho Blue markets for agents are:
- USDC/wETH (86% LLTV): Highest TVL, deep matching, stable utilization
- USDC/wstETH (86% LLTV): Yield-bearing collateral increases borrower demand
- USDT/wETH (86% LLTV): Alternative stablecoin exposure with similar characteristics
- WETH/wstETH (94.5% LLTV): ETH-denominated loop strategies; very high LLTV
- USDC/cbBTC (86% LLTV): Bitcoin-collateralized USDC loans; emerging but growing
4. Idle Capital Utilization
One of Morpho Blue's key advantages for agents is the ability to put idle capital to work without forfeiting liquidity. Unlike fixed-term bonds or locked staking, Morpho supply positions can be withdrawn at any time (subject to available liquidity).
The Idle Capital Problem
Most agents have capital sitting idle between active trades — waiting for entry signals, holding reserves for gas, maintaining collateral buffers. In traditional DeFi, this capital earns nothing. Morpho Blue enables agents to deploy this capital into lending markets while maintaining near-instant withdrawal access.
idle_capital_manager.py
class IdleCapitalManager:
"""
Manages an agent's idle capital by deploying it to Morpho Blue
while maintaining minimum liquid reserves.
"""
def __init__(
self,
morpho_contract,
wallet: str,
target_liquid_ratio: float = 0.15 # Keep 15% liquid at all times
):
self.morpho = morpho_contract
self.wallet = wallet
self.target_liquid = target_liquid_ratio
self.active_positions: dict = {} # market_id -> amount_supplied
def calculate_deployable_capital(
self,
total_portfolio_value: float,
reserved_capital: float
) -> float:
"""
Calculate how much capital can safely be deployed to Morpho.
Maintains minimum liquid buffer.
"""
liquid_needed = total_portfolio_value * self.target_liquid
deployable = max(0, total_portfolio_value - reserved_capital - liquid_needed)
return deployable
async def deploy_to_best_market(
self,
amount: float,
scored_markets: list,
min_apy: float = 0.04
) -> str:
"""Deploy capital to highest-scoring market above minimum APY"""
# Filter markets meeting minimum APY threshold
eligible = [
m for m in scored_markets
if m["supply_apy"] >= min_apy
]
if not eligible:
return None
# Sort by score descending
best_market = max(eligible, key=lambda m: m["score"])
market_id = best_market["market_id"]
# Execute supply transaction
await self.supply_to_market(market_id, amount)
# Track position
self.active_positions[market_id] = \
self.active_positions.get(market_id, 0) + amount
return market_id
async def supply_to_market(self, market_id: bytes, amount: float):
"""Supply assets to Morpho Blue market"""
# In production: call morpho.supply(marketParams, assets, shares, onBehalf, data)
print(f"Supplying {amount:.2f} USDC to market {market_id.hex()[:8]}...")
async def emergency_withdraw(self, min_return_fraction: float = 0.95):
"""
Withdraw all Morpho positions in emergency.
Some markets may have reduced liquidity — accept up to 5% slippage.
"""
withdrawn = {}
for market_id, amount in self.active_positions.items():
try:
# morpho.withdraw(marketParams, assets, shares, onBehalf, receiver)
withdrawn[market_id] = amount
print(f"Withdrew {amount:.2f} from market {market_id.hex()[:8]}")
except Exception as e:
print(f"Withdraw failed for {market_id.hex()[:8]}: {e}")
return withdrawn
Liquidity Monitoring
Before withdrawing from a Morpho Blue market, always check available liquidity: totalSupplyAssets - totalBorrowAssets. If utilization is near 100%, withdrawal may be delayed until borrowers repay. Maintain the idle buffer to avoid this situation.
5. Borrow Rate Optimization
For agents that need to borrow (e.g., to leverage long positions, fund operations, or execute arbitrage), Morpho Blue offers systematically lower rates than Aave or Compound due to P2P matching and isolated risk.
Borrow Rate Dynamics
Each Morpho Blue market uses an Interest Rate Model (IRM) contract. The default IRM (AdaptiveCurveIRM) adjusts rates based on utilization but also has an "adaptation" mechanism that slowly shifts the curve toward the current utilization level. This means:
- Rates respond quickly to utilization changes (price discovery is fast)
- Sustained high utilization raises the base rate over time
- Sustained low utilization lowers the base rate over time
- The curve is anchored at a target utilization of 90%
rate_optimizer.py
async def find_cheapest_borrow(
asset: str,
amount: float,
collateral: str,
markets: list[dict]
) -> dict:
"""
Find the cheapest Morpho Blue market to borrow `asset`
collateralized by `collateral`.
"""
eligible_markets = [
m for m in markets
if m["loan_token"] == asset
and m["collateral_token"] == collateral
and m["available_liquidity"] >= amount
]
if not eligible_markets:
return None
# Sort by borrow APY ascending (lowest cost first)
eligible_markets.sort(key=lambda m: m["borrow_apy"])
best = eligible_markets[0]
# Also calculate effective cost including P2P matching probability
# If matching ratio is high, borrow rate may be lower (P2P rate)
effective_rate = calculate_effective_borrow_rate(
pool_rate=best["borrow_apy"],
p2p_rate=best.get("p2p_borrow_rate", best["borrow_apy"]),
match_ratio=best.get("borrow_match_ratio", 0)
)
return {
"market": best,
"pool_rate": best["borrow_apy"],
"effective_rate": effective_rate,
"savings_vs_aave": best.get("aave_borrow_rate", 0) - effective_rate
}
def calculate_effective_borrow_rate(
pool_rate: float,
p2p_rate: float,
match_ratio: float
) -> float:
"""
Weighted average of P2P rate (for matched portion)
and pool rate (for unmatched portion).
"""
return match_ratio * p2p_rate + (1 - match_ratio) * pool_rate
LLTV and Collateral Efficiency
Morpho Blue offers much higher LLTV ratios than Aave for the same collateral pairs. For example, wETH/USDC at 86% LLTV vs Aave's 80% LTV allows agents to extract more capital per unit of collateral:
collateral = 100 ETH @ $2500 = $250,000
Aave max borrow: $250,000 * 0.80 = $200,000 USDC
Morpho max borrow: $250,000 * 0.86 = $215,000 USDC
Additional borrowing capacity: $15,000 USDC per $250K collateral
Capital efficiency improvement: 7.5%
6. MetaMorpho Vault Strategies
MetaMorpho is the vault layer built on top of Morpho Blue that automates multi-market capital allocation. Instead of manually managing positions across dozens of markets, agents deposit into MetaMorpho vaults that rebalance automatically based on the vault curator's strategy.
How MetaMorpho Works
A MetaMorpho vault is an ERC4626-compatible contract that:
- Accepts deposits of a single asset (e.g., USDC)
- Distributes capital across multiple Morpho Blue markets according to allocation caps
- Rebalances periodically as rates change
- Allows instant withdrawal (subject to aggregate market liquidity)
Well-known MetaMorpho vaults include Steakhouse USDC, Gauntlet USDC, and Re7 USDC — each with different risk parameters and market allocations.
Agent Strategy: Vault vs. Direct
vault_vs_direct.py
def should_use_vault_or_direct(
amount: float,
gas_cost_usd: float,
expected_hold_days: int,
direct_markets_count: int = 5,
vault_fee_bps: int = 50 # 0.5% annual performance fee typical
) -> str:
"""
Decide between MetaMorpho vault and direct market access.
"""
# Gas cost for direct multi-market allocation
direct_gas = gas_cost_usd * direct_markets_count * 2 # entry + exit
direct_gas_annual = direct_gas * (365 / expected_hold_days)
# Vault overhead as fraction of capital
vault_overhead = (vault_fee_bps / 10000) * amount
# Vault benefits: auto-rebalancing saves gas; typically within 0.3% of direct APY
direct_alpha_estimate = amount * 0.003 # 0.3% APY advantage of direct management
# Net benefit of direct management
net_direct_benefit = direct_alpha_estimate - direct_gas_annual + vault_overhead
if net_direct_benefit > 0 and amount > 50_000:
# Direct management pays off for larger positions
return "direct"
else:
# Vault is better for small amounts or short hold periods
return "vault"
Vault Selection Criteria
When choosing a MetaMorpho vault, agents should evaluate:
- Curator reputation: Gauntlet, Steakhouse, Re7 have track records
- Market allocation transparency: Check the vault's current market weights on Morpho's UI
- Performance fee: Typically 0.5-5% of yield; subtract from headline APY
- Historical APY stability: Low variance in returns indicates good risk management
- TVL trajectory: Growing TVL indicates curator trust; too fast growth may dilute rates
ERC4626 Integration
MetaMorpho vaults follow ERC4626 standard, making them trivially easy to integrate: vault.deposit(amount, receiver) to supply, vault.redeem(shares, receiver, owner) to withdraw. Agents can treat any MetaMorpho vault as a yield-bearing money market account.
7. Cross-Protocol Rate Arbitrage
The ultimate expression of lending optimization is cross-protocol rate arbitrage: borrowing at the lowest available rate on one protocol and lending at the highest available rate on another. Morpho Blue's lower costs make it the ideal borrowing venue, while its higher supply rates make it the ideal lending venue.
Rate Arbitrage Conditions
Pure rate arbitrage is profitable when:
profit_rate = lending_APY_on_A - borrowing_APY_on_B - gas_costs
> minimum_threshold (typically 0.5%+ annualized)
In practice, pure rate arbitrage quickly closes as agents pile in. The more sustainable opportunity is identifying persistent spreads that arise from:
- Oracle differences: Slightly different price feeds lead to different LTV assessments and utilization levels
- Gas threshold effects: Small spreads below gas cost are not arb'd by retail, but are profitable for agents with gas optimization
- Collateral type arbitrage: Using yield-bearing collateral (wstETH) on Morpho means the collateral itself earns while it's locked
- Maturity mismatches: Borrowing short-term (low rate), lending long-term (higher rate) — carry trade variant
cross_protocol_arb.py
import asyncio
import httpx
PROTOCOLS = {
"morpho": "https://blue-api.morpho.org/graphql",
"aave": "https://aave-api-v2.aave.com/data/markets",
"compound": "https://api.compound.finance/api/v2/ctoken",
}
async def fetch_all_lending_rates(asset: str = "USDC") -> dict:
"""Fetch supply and borrow rates for USDC across major protocols"""
rates = {}
async with httpx.AsyncClient() as client:
# Morpho Blue (GraphQL)
morpho_query = """
query {
markets(first: 20, where: {loanAsset: {symbol_in: ["USDC"]}}) {
items {
uniqueKey
state { supplyApy borrowApy utilization }
}
}
}
"""
morpho_resp = await client.post(
PROTOCOLS["morpho"],
json={"query": morpho_query}
)
morpho_data = morpho_resp.json()
markets = morpho_data.get("data", {}).get("markets", {}).get("items", [])
if markets:
best = max(markets, key=lambda m: m["state"]["supplyApy"])
rates["morpho_supply"] = best["state"]["supplyApy"]
cheapest = min(markets, key=lambda m: m["state"]["borrowApy"])
rates["morpho_borrow"] = cheapest["state"]["borrowApy"]
return rates
async def identify_arb_opportunities(min_spread: float = 0.005) -> list:
"""Find cross-protocol arbitrage opportunities above minimum spread"""
rates = await fetch_all_lending_rates("USDC")
opportunities = []
# Example: Check if Morpho supply rate > Compound borrow rate + gas
morpho_supply = rates.get("morpho_supply", 0)
morpho_borrow = rates.get("morpho_borrow", 0)
# Compare against hardcoded Aave/Compound rates (in production: fetch dynamically)
aave_supply = 0.045 # 4.5% example
compound_supply = 0.048 # 4.8% example
aave_borrow = 0.065
compound_borrow = 0.068
# If Morpho supply > Aave supply by >= min_spread
if morpho_supply - aave_supply >= min_spread:
opportunities.append({
"type": "supply_arbitrage",
"from": "aave",
"to": "morpho",
"spread": morpho_supply - aave_supply,
"action": f"Move USDC supply from Aave ({aave_supply:.2%}) to Morpho ({morpho_supply:.2%})"
})
# If Morpho borrow < Compound borrow by >= min_spread (borrow cheaper on Morpho)
if compound_borrow - morpho_borrow >= min_spread:
opportunities.append({
"type": "borrow_optimization",
"from": "compound",
"to": "morpho",
"spread": compound_borrow - morpho_borrow,
"action": f"Refinance USDC borrow from Compound ({compound_borrow:.2%}) to Morpho ({morpho_borrow:.2%})"
})
return opportunities
8. Python MorphoAgent
The complete MorphoAgent implementation manages supply positions across Morpho Blue markets, optimizes borrow rates, and executes cross-protocol opportunities automatically.
morpho_agent.py
"""
MorphoAgent: Lending rate optimization across Morpho Blue markets
Registers with Purple Flea for agent tracking and escrow settlements
"""
import asyncio
import os
import logging
from dataclasses import dataclass, field
from typing import Optional
from web3 import AsyncWeb3, AsyncHTTPProvider
import httpx
logging.basicConfig(level=logging.INFO)
log = logging.getLogger("MorphoAgent")
MORPHO_BLUE_ADDR = "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFc"
PURPLE_FLEA_API = "https://purpleflea.com/api"
@dataclass
class MorphoPosition:
market_id: str
loan_token: str
collateral_token: str
supply_amount: float = 0.0
borrow_amount: float = 0.0
collateral_amount: float = 0.0
current_supply_apy: float = 0.0
current_borrow_apy: float = 0.0
@dataclass
class AgentState:
positions: dict = field(default_factory=dict) # market_id -> MorphoPosition
total_supplied: float = 0.0
total_borrowed: float = 0.0
net_yield_rate: float = 0.0
class MorphoAgent:
def __init__(
self,
rpc_url: str,
private_key: str,
agent_id: str,
wallet: str,
capital_usdc: float = 10_000.0
):
self.w3 = AsyncWeb3(AsyncHTTPProvider(rpc_url))
self.private_key = private_key
self.agent_id = agent_id
self.wallet = wallet
self.capital = capital_usdc
self.state = AgentState()
# Strategy parameters
self.min_supply_apy = 0.04 # Don't supply below 4% APY
self.rebalance_threshold = 0.01 # Rebalance if rate diff > 1%
self.max_utilization = 0.92 # Don't supply to markets above 92% util
self.min_market_tvl = 5_000_000 # Only use markets with >$5M TVL
async def fetch_market_data(self) -> list[dict]:
"""Fetch market data from Morpho Blue API"""
query = """
query GetMarkets {
markets(first: 50) {
items {
uniqueKey
loanAsset { address symbol decimals }
collateralAsset { address symbol }
lltv
state {
supplyApy
borrowApy
utilization
totalSupplyAssets
totalBorrowAssets
liquidityAssets
}
oracleAddress
}
}
}
"""
async with httpx.AsyncClient(timeout=30) as client:
resp = await client.post(
"https://blue-api.morpho.org/graphql",
json={"query": query}
)
data = resp.json()
return data.get("data", {}).get("markets", {}).get("items", [])
def filter_markets(self, markets: list, loan_asset: str = "USDC") -> list:
"""Filter markets to agent's preferred parameters"""
filtered = []
for m in markets:
if m.get("loanAsset", {}).get("symbol") != loan_asset:
continue
state = m.get("state", {})
if state.get("supplyApy", 0) < self.min_supply_apy:
continue
if state.get("utilization", 1) > self.max_utilization:
continue
tvl = float(state.get("totalSupplyAssets", 0)) * 1e-6 # rough USD
if tvl < self.min_market_tvl:
continue
m["_score"] = self.score_market(m)
filtered.append(m)
filtered.sort(key=lambda m: m["_score"], reverse=True)
return filtered
def score_market(self, market: dict) -> float:
"""Score market for supply attractiveness (0-100)"""
state = market.get("state", {})
apy_score = min(state.get("supplyApy", 0) * 500, 40)
util = state.get("utilization", 0)
util_score = 30 if 0.65 <= util <= 0.85 else 15 if util < 0.65 else 5
tvl = float(state.get("totalSupplyAssets", 0)) * 1e-6
tvl_score = 20 if tvl > 100e6 else 15 if tvl > 20e6 else 10 if tvl > 5e6 else 0
lltv = float(market.get("lltv", 0)) / 1e18
lltv_score = 10 if lltv >= 0.86 else 5
return apy_score + util_score + tvl_score + lltv_score
async def rebalance_supply(self, markets: list):
"""Rebalance supply positions to highest-rated markets"""
log.info(f"Rebalancing across {len(markets)} eligible markets")
if not markets:
log.warning("No eligible markets found")
return
best_market = markets[0]
market_id = best_market["uniqueKey"]
supply_apy = best_market["state"]["supplyApy"]
# Check if we need to rebalance (is current best much better than current positions?)
current_positions = list(self.state.positions.values())
if current_positions:
current_best_apy = max(p.current_supply_apy for p in current_positions)
if supply_apy - current_best_apy < self.rebalance_threshold:
log.info(f"Rate diff {supply_apy - current_best_apy:.2%} below threshold, skipping rebalance")
return
# Execute supply to best market
alloc = self.capital * 0.8 # 80% to best market, 20% liquid reserve
await self.supply_to_market(market_id, best_market, alloc)
async def supply_to_market(self, market_id: str, market: dict, amount: float):
"""Execute supply transaction to Morpho Blue"""
log.info(
f"Supplying ${amount:,.2f} USDC to market {market_id[:8]}... "
f"(APY: {market['state']['supplyApy']:.2%})"
)
# Record position
self.state.positions[market_id] = MorphoPosition(
market_id=market_id,
loan_token=market.get("loanAsset", {}).get("symbol", "USDC"),
collateral_token=market.get("collateralAsset", {}).get("symbol", ""),
supply_amount=amount,
current_supply_apy=market["state"]["supplyApy"],
)
self.state.total_supplied += amount
# In production: build tx for morpho.supply(marketParams, assets, 0, wallet, b"")
# and broadcast via self.w3
async def calculate_portfolio_yield(self) -> float:
"""Calculate weighted average yield across all positions"""
total = sum(p.supply_amount for p in self.state.positions.values())
if total == 0:
return 0.0
weighted = sum(
p.supply_amount * p.current_supply_apy
for p in self.state.positions.values()
)
return weighted / total
async def report_activity(self):
"""Report to Purple Flea agent registry"""
yield_rate = await self.calculate_portfolio_yield()
async with httpx.AsyncClient() as client:
try:
await client.post(
f"{PURPLE_FLEA_API}/agents/{self.agent_id}/activity",
json={
"action": "morpho_rebalance",
"positions": len(self.state.positions),
"total_supplied_usd": self.state.total_supplied,
"weighted_apy": yield_rate,
},
timeout=10
)
except Exception as e:
log.warning(f"Failed to report to Purple Flea: {e}")
async def run(self):
"""Main agent loop — fetch markets, rebalance, report"""
log.info(f"MorphoAgent started | ID: {self.agent_id} | Capital: ${self.capital:,.0f}")
while True:
try:
# Fetch and filter markets
all_markets = await self.fetch_market_data()
log.info(f"Fetched {len(all_markets)} total markets")
eligible = self.filter_markets(all_markets, loan_asset="USDC")
log.info(f"{len(eligible)} eligible markets after filtering")
if eligible:
top3 = eligible[:3]
for m in top3:
log.info(
f" {m['collateralAsset']['symbol']}/USDC | "
f"APY: {m['state']['supplyApy']:.2%} | "
f"Score: {m['_score']:.1f}"
)
# Rebalance positions
await self.rebalance_supply(eligible)
# Report to Purple Flea
await self.report_activity()
log.info("Cycle complete. Sleeping 5min...")
await asyncio.sleep(300)
except Exception as e:
log.error(f"Error in MorphoAgent loop: {e}", exc_info=True)
await asyncio.sleep(60)
async def main():
agent = MorphoAgent(
rpc_url=os.getenv("ETH_RPC_URL", "https://eth.llamarpc.com"),
private_key=os.getenv("PRIVATE_KEY", ""),
agent_id=os.getenv("AGENT_ID", "morpho-agent-001"),
wallet=os.getenv("WALLET_ADDRESS", ""),
capital_usdc=float(os.getenv("CAPITAL_USDC", "10000")),
)
await agent.run()
if __name__ == "__main__":
asyncio.run(main())
Integration with Purple Flea Escrow
When MorphoAgent generates yield, it can distribute profits to multiple stakeholders — agent operator, stakers, or partner protocols — using Purple Flea's trustless escrow. Set up an escrow agreement where yield above the hurdle rate (e.g., 5% APY) automatically flows to the agent operator, while the principal remains protected.
Start Earning with Morpho on Purple Flea
Register your lending agent, claim free startup capital from the faucet, and deploy MorphoAgent to start earning optimized lending yields. Use Purple Flea escrow for trustless profit sharing.
Register as Agent Get Free CapitalSummary
Morpho Blue gives AI agents a structural advantage in DeFi lending through P2P matching, permissionless market creation, and superior capital efficiency. The key takeaways are: use Morpho's market scoring framework to identify the best supply opportunities, monitor matching ratios to ensure P2P rates are being captured, deploy idle capital through MetaMorpho vaults for automated management, and systematically compare rates across Aave, Compound, and Morpho to capture cross-protocol spreads.
The MorphoAgent implementation above provides a production-ready starting point. Pair it with Purple Flea's faucet for initial capital and escrow for trustless profit distribution to build a complete autonomous lending operation.