Protocols

Lending, vaults and earn

Supply, borrow and loop on lending markets, deposit in vaults, lock a fixed rate on Pendle, or let earn route an asset to the best rate, all from Flowscript.

Lending markets#

Aave, Spark, Compound, Kamino and marginfi share one surface:

ReadAction
<id>.supplyApy("chain:asset", interval)<id>.supply({ asset, usd })
<id>.supplied(), <id>.borrowed()<id>.withdraw({ asset, all: true })
<id>.healthFactor()<id>.borrow({ asset, usd }), <id>.repay({ asset, all: true })

Sizes are units of the token, dollars at the protocol's price, a percent of what's there, or all. Aave and Spark also take E-mode and collateral switches, so a strategy can loop, roll a borrow or swap collateral. A move the protocol would refuse reverts with the contract's own reason.

Vaults#

Morpho, Euler, Yearn, Fluid, Gearbox, Sky, Ethena, Maple and others: <id>.apy(…), <id>.deposit, <id>.withdraw and <id>.deposited(). Euler, Yearn and Morpho also take any vault by its address (base:0x…), checked on chain when the strategy is saved.

Fixed rates on Pendle#

Buy a Pendle PT to lock its implied rate to maturity: pendle.impliedApy("ethereum:0x…", interval), pendle.buy, pendle.sell and pendle.held(). The classic pairing: hold the PT while its implied rate beats Aave's supply rate by a margin, and go back to Aave when the gap closes.

Flowscript
uses { pendle: "^1", aave: "^1" }
const fixed = pendle.impliedApy("ethereum:roll:siusd", interval);
const float = aave.supplyApy("ethereum:usdc", interval);
const spread = fixed - float;
metric("spread", spread);
when (spread > 3 && pendle.held("ethereum:roll:siusd") == 0) {
  aave.withdraw({ asset: "ethereum:usdc", all: true });
  pendle.buy({ asset: "ethereum:roll:siusd", all: true });
}
when (spread < 0.5 && pendle.held("ethereum:roll:siusd") > 0) {
  pendle.sell({ asset: "ethereum:roll:siusd", all: true });
  aave.supply({ asset: "ethereum:usdc", all: true });
}

ethereum:roll:siusd follows the current Pendle market for an asset and rolls to the next one at maturity.

earn: the best rate for an asset#

earn routes an asset instead of naming a protocol. earn.apy("usdc", interval) is the best rate across live USDC markets; earn.deposit, earn.withdraw and earn.rebalance({ minGainPct, costUsd }) move it; earn.deposited() and earn.heldApy() read the book.

Give rebalance a minGainPct of a point or more and a costUsd of what one move costs, so it doesn't bridge back and forth on noise.

Reading the edge#

Each protocol has its own guide (in the module's page, or get_protocol_guide for an AI) saying where its edge is and what the paper book leaves out: reward tokens, withdrawal queues, cooldowns, oracle quirks. Read it before designing a strategy on it.