
YieldSolver
DeFi deposits chase the best APY and fill 1inch intents on Base, earning yield and fees together
Demo
About
YieldSolver makes the same capital work twice. Money sitting in lending markets like Morpho, Aave and Fluid earns interest, but it does nothing else. Meanwhile, intent protocols like 1inch Fusion need liquidity at the exact moment an order is filled. YieldSolver connects the two: deposits keep earning lending yield, and the same deposits are used to fill 1inch Fusion swap intents on Base, earning fees and spread on top. The recommended mode is self-custody. A user supplies USDC or WETH to Morpho, Fluid or Aave and keeps the interest-bearing shares in their own wallet. With a single approval and a 1inch Aqua strategy, those shares become shared liquidity. They are only moved inside a transaction that must return them, so the user never deposits into our vault and can stop at any time. Three things then happen to the same position: 1. A keeper moves the shares to whichever listed market pays the best APY. 2. Our resolver borrows them just in time to fill a Fusion order, and repays them with a fee in the same transaction. 3. The shares also run as a 1inch SwapVM order that quotes the Chainlink price plus a spread, so any taker can buy from the wallet's inventory. All fees come back to the wallet as more shares, so the capital never stops earning. For users who prefer a managed product there are three vaults: A. A USDC yield vault that lends just in time to the resolver. B. Inventory market making profiles (70/30, 50/50, 30/70 USDC/ETH) that fill orders from stock at oracle price plus spread, stay inside a plus or minus 5 point band, and lend idle inventory on Aave. C. A conditional ETH carry vault. It keeps WETH as Aave collateral and borrows USDC into the best whitelisted ERC-4626 vault only while the spread beats the cost of getting in and out, then exits on its own when the spread disappears. Safety rules live in the contracts, not in the bots: LTV caps, public deleverage above 40 percent, trade size limits, price staleness checks, whitelisted markets and routers, and on-chain rejection of any loss-making fill. Everything is live on Base Sepolia with a dashboard showing where every dollar sits, what each wallet earned, and every fill with its transaction.
How it's made
Contracts are written in Solidity 0.8.30 with Foundry, and bots are TypeScript with viem. The frontend is a Vite and TypeScript dashboard. Everything runs in Docker and is deployed on Base Sepolia. 1inch Fusion: users sign gasless intents with the official fusion-sdk and limit-order-sdk. 1inch has no testnet, so we deployed the unmodified Limit Order Protocol v4 and Fusion SimpleSettlement contracts ourselves and wrote a relayer that validates orders the same way the 1inch API does (hash, EIP-712 signature against the deployed domain, resolver whitelist, balance, allowance, expiry). Our resolver bot takes each order at its current Dutch auction price and simulates every possible source: JIT from the vault, inventory, JIT from a wallet, market making from a wallet, and SwapVM. It fills with the most profitable one. A minimum profit is enforced on-chain, so a bad simulation can never lose money. 1inch Aqua: this is the core of the project. We wrote three Aqua apps. AquaYieldApp is the self-custody app: the maker is a user wallet, and the committed Aqua tokens are ERC-4626 lending shares instead of plain tokens, so every committed budget keeps earning yield. It supports keeper rebalancing between markets, flash loans with a fee to the maker, and oracle priced swaps with inventory skew and a band. JitLiquidityApp and OracleSwapApp power the two managed vaults. Every pull is checked to come back within the same transaction. 1inch SwapVM: we built our own SwapVM router from the unmodified SwapVM 1.2 core plus 1inch's Aqua instruction set, and added two custom instructions. YieldOracleSwap (opcode 64) does oracle plus spread market making on yield-bearing shares. It converts share balances to underlying assets, prices at Chainlink plus spread with a skew toward the maker's target ratio, enforces a band and a max trade size, converts back to shares, and always rounds in the maker's favour. SequencerGuard (opcode 65) blocks trades while the Base sequencer is down. Wallets ship SwapVM orders over the same shares they committed to AquaYieldApp, which shows Aqua's real promise: one position backing several strategies at once. We ran 1inch's own CoreInvariants suite against our program (symmetry, quote and swap consistency, monotonicity, additivity, maker-favouring rounding), and it passes. Base and Chainlink: all contracts run on Base Sepolia. Lending markets, the oracle and the router are mocks driven by a simulator that mirrors the real Chainlink ETH/USD price from Base mainnet, so the demo moves with the real market. A Base mainnet fork test runs the carry vault against real Aave, Morpho vaults and the real Aave oracle. Curvegrid MultiBaas: we linked our 10 main contracts to a MultiBaas deployment on Base Sepolia. Its transaction explorer decodes our nested transactions (resolver, SwapVM, Aqua pull and push, share redeem, LOP fill) with function arguments and events, without verifying sources on Basescan. Its event indexing tracks our contracts' events. Notable hacks: 1. Aqua only moves tokens, so to make liquidity earn while committed we commit ERC-4626 shares, then price in assets and settle in shares. We wrote a non-rebasing ERC-4626 wrapper for Aave so fixed Aqua budgets stay meaningful. 2. For SwapVM fills, the resolver receives the wallet's shares first, redeems them inside SwapVM's taker callback, fills the Fusion order with the proceeds, then mints fresh shares of the other asset to pay the wallet back, all in one transaction. 3. We found that route comparison was unfair, because the surplus from the auction decaying before inclusion was counted for JIT routes but not for exact-out routes. The resolver now ranks routes like for like. 4. The SwapVM router came out over the 24 KB contract size limit. We brought it down to 21.4 KB with a size-optimised via-IR build. 5. The carry vault only enters when expected profit over 24 hours covers entry plus exit gas three times. It uses hysteresis to exit, and the contract lets anyone deleverage if LTV drifts too high. 6. The dashboard shows realised returns until a full day of data exists instead of annualising a few hours of flow. Testing: 157 Foundry tests (unit, fuzz, invariant, Base mainnet fork) and an end-to-end script that spins up anvil, deploys everything, runs all bots, and asserts that orders fill through every route and that wallets earn.