DeFi

What Are Real World Assets (RWA) in DeFi and How Bots Can Trade Them

Real World Assets (RWA) — tokenized treasuries, bonds, real estate, and commodities — are the fastest-growing DeFi category in 2026. Learn how they work and how automated bots can access this emerging yield source.

A
AI Agents Hub·2026-03-27·5 min read·835 words

Builder of AI agents, crypto trading bots, and open-source automation tools. Sharing practical guides on how to build, deploy, and profit from AI and DeFi technology.

The RWA Revolution

By 2026, over $20 billion in real-world assets have been tokenized on blockchain networks. The biggest categories:

  • US Treasury Bills: 4-5% yield, government-backed
  • Corporate bonds: 5-8% yield
  • Real estate debt: 7-12% yield
  • Trade finance: 8-15% yield
  • Private credit: 9-15% yield

For DeFi users and bots, RWAs solve a fundamental problem: sustainable yield. Unlike liquidity mining rewards that inflate away, RWA yields come from real economic activity.

Key RWA Protocols in 2026

Ondo Finance (Best for Treasuries)

Ondo tokenizes US Treasury bills and money market funds into on-chain tokens:

  • USDY: Yield-bearing stablecoin backed by US Treasuries (~5% APY)
  • OUSG: Tokenized short-term US government bonds
# Ondo USDY is ERC-20 — interact like any token
from web3 import Web3

USDY_CONTRACT = '0x96F6eF951840721AdBF46Ac996b59E0235CB985C'
ONDO_RPC = 'https://mainnet.base.org'  # USDY is on Base chain

w3 = Web3(Web3.HTTPProvider(ONDO_RPC))

def get_usdy_yield() -> float:
    """Fetch current USDY yield from Ondo API"""
    import requests
    response = requests.get('https://api.ondo.finance/api/v1/rates')
    data = response.json()
    return data.get('usdyRate', 0)

print(f"Current USDY yield: {get_usdy_yield():.2f}% APY")

Centrifuge (Real Estate + Corporate Credit)

Centrifuge connects DeFi capital with real-world borrowers:

  • Businesses upload invoice/loan data as NFTs
  • DeFi users fund these through Centrifuge pools
  • Pools earn yield from real business cash flows
# Centrifuge uses Substrate (Polkadot parachain) + Ethereum bridge
# Access via their REST API or The Graph subgraph

import requests

def get_centrifuge_pools() -> list:
    """Get all active Centrifuge pools with yield data"""
    query = """
    {
      pools(first: 20, orderBy: sumBorrowedAmountByPeriod, orderDirection: desc) {
        id
        name
        currency { symbol }
        currentJuniorYield
        currentSeniorYield
        totalDebt
        totalBorrowed
        seniorTokenPrice
      }
    }
    """
    response = requests.post(
        'https://api.thegraph.com/subgraphs/name/centrifuge/tinlake',
        json={'query': query}
    )
    return response.json()['data']['pools']

pools = get_centrifuge_pools()
for pool in pools[:5]:
    print(f"{pool['name']}: Senior {pool['currentSeniorYield']:.1f}% | Junior {pool['currentJuniorYield']:.1f}%")

Maple Finance (Institutional Lending)

Maple provides undercollateralized loans to institutions (market makers, trading firms). Yields are higher (8-12%) but require trust in the pool delegate's underwriting.

OpenEden (Tokenized T-Bills on Ethereum)

OpenEden's TBILL token wraps US Treasury bills directly on Ethereum, providing institutional-grade security with on-chain accessibility.

Building an RWA Yield Optimizer

from dataclasses import dataclass

@dataclass
class RWAProtocol:
    name: str
    apy: float
    min_deposit_usd: float
    lock_period_days: int
    chain: str
    risk_level: str  # low, medium, high
    contract_or_url: str

def get_all_rwa_yields() -> list[RWAProtocol]:
    """Fetch current yields from all major RWA protocols"""
    protocols = []
    
    # Ondo USDY
    protocols.append(RWAProtocol(
        name="Ondo USDY",
        apy=get_usdy_yield(),
        min_deposit_usd=500,
        lock_period_days=0,
        chain="base",
        risk_level="low",
        contract_or_url=USDY_CONTRACT
    ))
    
    # Fetch from Maple API
    maple_pools = get_maple_pools()
    for pool in maple_pools:
        protocols.append(RWAProtocol(
            name=f"Maple - {pool['name']}",
            apy=pool['apy'],
            min_deposit_usd=pool['minDeposit'],
            lock_period_days=pool['lockup'],
            chain="ethereum",
            risk_level="medium",
            contract_or_url=pool['contractAddress']
        ))
    
    return protocols

def optimize_rwa_allocation(capital_usd: float, max_lockup_days: int = 30) -> list:
    """Find optimal RWA allocation given capital and lockup constraints"""
    protocols = get_all_rwa_yields()
    
    # Filter by lockup tolerance
    eligible = [p for p in protocols if p.lock_period_days <= max_lockup_days]
    
    # Sort by risk-adjusted yield
    risk_discount = {'low': 1.0, 'medium': 0.85, 'high': 0.7}
    eligible.sort(key=lambda p: p.apy * risk_discount[p.risk_level], reverse=True)
    
    # Allocate capital (diversify across top 3)
    allocation = []
    remaining = capital_usd
    max_per_protocol = capital_usd * 0.40  # Max 40% in any single protocol
    
    for protocol in eligible[:3]:
        if remaining <= 0:
            break
        if capital_usd < protocol.min_deposit_usd:
            continue
        
        amount = min(max_per_protocol, remaining)
        allocation.append({
            'protocol': protocol.name,
            'amount_usd': amount,
            'apy': protocol.apy,
            'annual_yield': amount * (protocol.apy / 100),
            'chain': protocol.chain,
        })
        remaining -= amount
    
    total_yield = sum(a['annual_yield'] for a in allocation)
    weighted_apy = total_yield / capital_usd * 100
    
    print(f"\nRWA Allocation for ${capital_usd:,.0f}:")
    for a in allocation:
        print(f"  {a['protocol']}: ${a['amount_usd']:,.0f} @ {a['apy']:.1f}% = ${a['annual_yield']:,.0f}/yr")
    print(f"\nWeighted APY: {weighted_apy:.2f}% → ${total_yield:,.0f}/year")
    
    return allocation

Comparing RWA vs DeFi Native Yields

| Category | Typical APY | Risk | Volatility | Liquidity | |----------|------------|------|-----------|---------| | Tokenized T-Bills | 4-5% | Very Low | None | High | | Corporate credit | 6-9% | Low-Medium | Low | Medium | | Private credit | 9-15% | Medium | Low | Low | | Aave/Compound lending | 3-8% | Low | High | High | | DeFi LP farming | 10-30% | Medium-High | Very High | Medium | | Liquidity mining | 20-100% | Very High | Extreme | Variable |

The key insight: RWA yields (4-12%) are lower than DeFi native peaks but dramatically more stable and predictable. For the "safe" portion of your portfolio, RWAs beat traditional bank yields while staying on-chain.

Automating RWA Positions

For USDY and similar ERC-20 RWA tokens, automation is straightforward:

async def auto_allocate_idle_usdc(min_idle_days: int = 3, min_amount_usd: float = 1000):
    """Move idle USDC into USDY when it's been sitting unused for 3+ days"""
    
    # Check USDC balance
    usdc_balance = await get_usdc_balance()
    
    if usdc_balance < min_amount_usd:
        return
    
    # Check if USDC has been idle
    last_used = await get_last_usdc_activity()
    if (datetime.now() - last_used).days < min_idle_days:
        return
    
    # Swap USDC → USDY
    print(f"${usdc_balance:,.0f} USDC idle for {min_idle_days}+ days")
    print(f"Moving to USDY for {get_usdy_yield():.1f}% APY")
    
    await swap_usdc_to_usdy(usdc_balance)

RWA tokenization is still early — expect yields to compress as more capital flows in. The best time to allocate is now, while institutional-grade yields are still accessible to retail DeFi participants.

Related Articles