
Seasonals
DeFi time layer: a calendar of when your positions mature, plus one-tap AI Agent rebalances
Demo
About
Seasonals is a time layer for DeFi. Portfolio trackers show you a snapshot of what you hold. Seasonals shows you a schedule: when each position needs attention. Pendle PT maturities, Ethena sUSDe cooldown ends, Lido withdrawal claims, Uniswap Continuous Clearing Auction start / end / claim / refund blocks, and 1inch Aqua strategy reviews all become dated events on one calendar. Every event carries an action. Tap a Pendle maturity and you get a redeem plan; tap a finished Ethena cooldown and you get an unstake plan. Plans are built as unsigned transactions, checked against live mainnet state with eth_call, and shown with warnings before you approve. Nothing is signed until you press one button. Simulate, approve and execute happen on one screen, with no tab hopping. The same data is exposed to AI agents through an MCP server. An agent (we use Claude) can read your holdings and the yield menu, preview each step, and submit a rebalance proposal of up to six steps. Our demo strategy, "Lemon Ladder", swaps idle USDC to USDe via the Uniswap Trading API, stakes it into sUSDe, and ships part of it as a pegged-stable LP strategy on 1inch Aqua. The backend turns the proposal into a Strategy Brief with before / after allocation and a blended APY computed deterministically, so the LLM names the strategy but cannot invent the numbers. The proposal appears as a card in the web app and as a calendar event. You approve it with one tap, or reject it. Only then do the transactions execute (eight in total for Lemon Ladder, including approvals). Safety is fail-closed. Price-dependent steps are gated by Chainlink and Pendle TWAP oracles: stale or unavailable data blocks execution, and divergence above 5 percent blocks it too. Agents can propose but never execute without a human approval token bound to a bundle hash. Seasonals never holds private keys. For the hackathon, reads are against live mainnet and execution runs on a local mainnet fork. Humans read the calendar. Agents read the API. Same source of truth.
How it's made
Seasonals is a pnpm monorepo with a shared TypeScript lib, a Fastify BFF, a React 19 web app (Vite, TanStack Query, Zustand, Recharts) and an MCP server (stdio). All three consume the same types from lib, so the calendar and the agent API cannot drift apart. Ethereum access goes through viem. The BFF reads mainnet state (Pendle SY / PT / YT balances, sUSDe cooldowns, Lido WithdrawalQueue requests, CCA bids) and turns it into UnifiedTimeEvents. Each event maps to an unsigned plan: encoded calldata plus an eth_call simulation against live mainnet, returned with warnings and never broadcast. Partner integrations: - Uniswap: we indexed all four Continuous Clearing Auction factory deployments (v1.0.0 to v2.1.0), about 2.28M blocks in 10k-block slices with resumable progress, and found 330 auctions. Start, end, claim and refund become calendar events, and exitBid / claimTokens become plans. The Trading API (/check_approval, /quote with generatePermitAsTransaction) routes USDC to USDe before an Ethena deposit. - 1inch Aqua + SwapVM: the agent can ship a PEGGED_STABLE LP strategy using AquaPeggedAmmStrategy on the deployed AquaSwapVMRouter, with app-side parameter validation (band 10 to 200 bps, fee 1 to 30 bps, review date within 180 days). Shipping creates a "strategy review" event with a dock action. - Chainlink: USDe/USDC peg guard (plus or minus 50 bps, stale rounds rejected) in front of every swap and Aqua ship. Pendle trades are guarded by the PYLpOracle 15-minute TWAP, with a 2 percent warning and a 5 percent block. - Pendle, Ethena and Lido via their contracts and public APIs for yields. Execution runs on a local Anvil fork of mainnet. The BFF verifies the target is Anvil with chainId 1, rebuilds the plan against fork state, then uses anvil_impersonateAccount to send as the owner. This let us run full end-to-end flows, including the eight-transaction Lemon Ladder rebalance, without a hot wallet. The demo owner is a large public exchange address that we impersonate. Hacky bits we are a little proud of: Anvil only accepts the fork URL as an argument, so we run a tiny local RPC proxy that injects the Infura key from env, keeping it out of the process list and logs. The 1inch SDK ESM build has broken internal imports, so we load it via CJS require. CCA deployment blocks are not published, so we binary-searched eth_getCode to find them. The agent proposal flow uses a bundle hash over {id, owner, steps} so an approval cannot be replayed against a modified proposal, and the MCP server exposes execution only after a human approves in the web UI or in chat. Numbers are strings in smallest units at every API boundary and bigint inside the service. No floats touch money.