Skip to content
Yield Engine

SDK Adapters

29 standalone Python adapters reading DeFi protocol smart contracts via JSON-RPC batch calls through archive RPC. Zero pip dependencies. Covers Aave, Morpho, Pendle, Euler, and 25 more.

The Yield Engine discovers positions across 15 chains. SDK adapters are the modules that do the actual contract reads — each one knows its protocol's quirks, correct APY fields, and data traps.

How adapters work

Each SDK adapter is a standalone Python module that queries protocol smart contracts directly via JSON-RPC. No pip dependencies -- stdlib only. No cached APIs, no third-party aggregator data. The number you see is computed from the contract state that exists right now.

SMART CONTRACTS on-chain state SDK ADAPTER Python stdlib JSON-RPC batch INFURA Archive nodes via SOCKS5 yelda.db SQLite APY computed from live state → saved after each batch → never sequential eth_call
DeFiLlama is used as a protocol registry only. All APY numbers come from direct on-chain computation via archive RPC nodes. If RPC is unreachable, the adapter halts with HALT_RPC_UNAVAILABLE rather than falling back to cached or third-party data.

Protocol coverage

ProtocolCategoryChains
Aave V3LendingEthereum, Arbitrum, Base, Optimism, Polygon
Morpho BlueCurated lendingEthereum, Base
PendleYield tokenizationEthereum, Arbitrum
EulerLendingEthereum
FluidLendingEthereum
CompoundLendingEthereum, Base, Arbitrum
Curve / ConvexDEX LP / CRV boostEthereum, Arbitrum
EthenaSynthetic dollarEthereum
Lido / Rocket PoolLiquid stakingEthereum
EigenLayerRestakingEthereum
BeefyAuto-compounding25+ chains
Yearn V3Yield aggregatorEthereum
Jito / KaminoStaking / LendingSolana
HyperliquidPerp DEXHyperEVM
+ 15 more adapters across lending, DEX LP, perps, and restaking

APY field mapping

Every protocol reports APY differently. Adapters normalize everything into a single effective_apy column:

Morpho
Uses: net_apy
Trap: raw apy can be 50x higher than net yield
Pendle
Uses: apy_implied (PT)
Trap: No single apy field exists at all
Ethena
Uses: protocol_yield
Trap: Different meaning per entry type
Convex
Uses: Filtered pools
Trap: Many pools report $0 TVL — garbage data
Yearn
Uses: Smoothed apy
Trap: Can spike 500%+ on single-day data
Aave
Uses: supply_apy
Trap: Usually correct, but verify reward tokens

Adapter anatomy

Every adapter follows the same structure:

class AaveAdapter:
    """Direct contract reads for Aave V3 markets."""

    POOL_ADDRESS = "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2"
    CHAINS = ["ethereum", "arbitrum", "base", "optimism", "polygon"]

    def fetch_pools(self, chain: str) -> list[dict]:
        # 1. Multicall getReservesList()
        # 2. For each reserve: getReserveData()
        # 3. Compute supply_apy from liquidity rate
        # 4. Return normalized pool objects
        ...

    def compute_apy(self, liquidity_rate: int) -> float:
        # RAY = 10**27, convert on-chain rate to annualized %
        return ((1 + liquidity_rate / 10**27) ** 31536000 - 1) * 100
All adapters use JSON-RPC batch calls via eth_call. Never sequential calls — always batched. Results are saved to DB after each batch, not at end.

Adapters produce raw position data. Before it reaches your board, every position goes through the verification pipeline — exploit cross-reference, TVL checks, APY consistency, and contract verification.