Skip to content
tedinrocPublic

About

Isotherm — daily city-temperature strike ladders on Monad: YES/NO tokens on Kuru order books, settled by Chainlink CRE from airport METAR. Monad Metropolis hackathon (testnet).

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Isotherm logo: a thermometer whose mercury stops on an isotherm line

Isotherm

Daily city-temperature strike ladders on Monad.
"Will Taipei's high reach ≥ 30 °C tomorrow?" One fully collateralized YES/NO pair per strike, one onchain Kuru order book per strike, settled from the airport's METAR reports by a Chainlink CRE workflow.

Live on Monad testnet 149 Foundry tests passing Sourcify exact_match Settlement rule matches Polymarket MIT license

Monad Metropolis, Track 01 (Onchain Finance & Trading). Isotherm runs on Monad testnet (chain 10143) with faucet AUSD.

Phone app (PWA) https://isotherm.pages.dev
API (same origin) /api/health, /api/snapshot, /api/stats, /api/settlements
Contracts (Sourcify exact_match) Resolver · CollateralVault · IsothermZap · all addresses
Agent plugin packages/mm-plugin: mm weather … for the MetaMask Agent Wallet; agent skill in skills/isotherm-weather-trading/SKILL.md
Videos Technical demo (2:58) · Pitch (1:55) · Dynamic sign-in flow (1:12) · Chainlink CRE live run (1:41) · MetaMask Agent Wallet flow (3:07)
Design docs ARCHITECTURE.md · docs/OPERATIONS.md · logo and cover in brand/

Explorer links (note added 2026-10-26, after submission; no code changed): MonadVision now keeps transaction pages for only about 9 days, so the transaction links in this README open an error page there. Every one of those transactions is still on chain with status success. To view one, open the same hash on MonadScan: https://testnet.monadscan.com/tx/<hash>. Contract and address pages on MonadVision still load.

The problem and the product

Polymarket already trades daily high-temperature markets that resolve on a public airport weather report. Each city-day is split into 11 mutually exclusive temperature buckets (as of October 2026), traded on an off-chain-matched order book. Isotherm is built for the traders and bot builders already on those markets, and for agents through the MetaMask plugin.

Isotherm rebuilds the same risk as a strike ladder: for one station and one local day, a set of cumulative "Tmax ≥ k °C" strikes, each with its own onchain Kuru order book on Monad. Each strike is a complete set, 1 YES + 1 NO backed by exactly 1 AUSD, minted as plain ERC-20s. YES trades on the strike's book; NO is one tap away. A market maker quotes every book around the Polymarket-implied probability, and after the local day ends a Chainlink CRE workflow reads the station's METAR reports from two independent archives and settles the whole ladder with one attested report. Winners redeem for 1 AUSD 15 minutes later.

The vision: weather risk as composable onchain instruments. Every strike is a public book that people, contracts and agents can read and trade, with settlement anyone can recompute from public data.

How it works

flowchart LR
  subgraph DATA["Keyless public data"]
    PM["Polymarket prices<br/>implied P(Tmax ≥ k)"]
    OM["Open-Meteo forecasts<br/>guardrail model"]
    IEM["IEM METAR archive"]
    AWC["aviationweather.gov METAR"]
    OG["Ogimet METAR<br/>fallback"]
  end
  subgraph SVC["Isotherm services"]
    MK["Market maker<br/>daily roll + quotes"]
    WEB["Phone PWA<br/>Dynamic email login"]
    API["API<br/>drip + gasless relayer + stats"]
    MMP["MetaMask Agent Wallet<br/>plugin"]
    CRE["Chainlink CRE<br/>settlement workflow"]
  end
  subgraph CHAIN["Monad testnet"]
    VAULT["CollateralVault<br/>YES/NO OutcomeTokens"]
    ZAP["IsothermZap"]
    KURU["Kuru order books<br/>one per strike"]
    FWD["CRE forwarder<br/>(MockKeystoneForwarder)"]
    RES["Resolver"]
  end
  PM & OM --> MK
  MK -->|"createLadder, mintSet"| VAULT
  MK -->|"new book per strike, quotes"| KURU
  WEB --> API
  API -->|"relays signed AUSD authorizations"| VAULT
  WEB & MMP -->|"buy / sell"| ZAP
  ZAP --> KURU & VAULT
  IEM & AWC --> CRE
  OG -.-> CRE
  CRE -->|"EIP-712 attested report"| FWD
  FWD --> RES
  RES -->|"Tmax or void"| VAULT
Loading
  1. Open. From noon the day before, the roll job picks up to four strikes nearest the Polymarket-implied median (none with an implied probability outside 5–95 %; up to six before the 2026-10-09 release), creates the ladder (two token clones per strike, one transaction), opens one Kuru YES/AUSD book per strike and registers it as the strike's canonical market in the Zap.
  2. Quote. The maker mints inventory and quotes every book around the Polymarket-implied P(Tmax ≥ k), conditions on the day's observed METAR maximum, and pulls all quotes 10 minutes before close.
  3. Trade. Buy YES in one transaction through the Zap; buy NO as mintSet + sellYes with an exact price bound; sell, or merge a YES+NO pair back into 1 AUSD at any time.
  4. Settle. From 02:00 local the next day, the CRE workflow fetches every METAR and SPECI report for the local day. Two complete sources that agree produce an attested report. Disagreement or missing data stays pending with hourly retries, and voids at 0.5/0.5 only after 36 hours.
  5. Redeem. A settled result is final after a 15-minute guardian challenge window; YES pays 1 AUSD if Tmax ≥ k, NO otherwise.

The settlement rule reproduces how Polymarket's daily-high markets resolve: the maximum integer °C in the METAR temperature group over all reports in the station's local day. Replayed against every Polymarket event that resolved on the same station (spikes/weather/RESULT.md):

Station Polymarket events Isotherm rule agrees
Taipei Songshan (RCSS), 2026-04-05 → 10-05 184 183 / 184 (on the remaining day, two independent METAR archives both hold a 25 °C report)
Tokyo Haneda (RJTT), 2026-03-10 → 10-05 209 209 / 209

What's live

  • Daily Taipei ladders since 2026-10-07. Every day at 12:00 Taipei the next day's ladder opens, with one Kuru book per strike. By 2026-10-10 that is Oct 8 (≥ 28–31 °C), Oct 9 (≥ 28–32), Oct 10 (≥ 28–31) and Oct 11 (≥ 29–31): 16 Kuru books; the live app and /api/snapshot show the current ladder. The first went live with 27 transactions in 64 seconds: the ladder, four Kuru books, the maker's inventory and the opening quotes (createLadder, docs/evidence/golive/).

  • Settled automatically, matching Polymarket. Each ladder settles at 02:05 Taipei after its day ends, through the official CRE CLI, and every result Polymarket has resolved so far equals its high for the same Taipei day (/api/settlements):

    Taipei day High Polymarket Settlement tx
    Thu 2026-10-08 28 °C 28 °C 0x65eee8ef…963d
    Fri 2026-10-09 29 °C 29 °C 0xdfd28ea5…3ecd
    Sat 2026-10-10 30 °C 30 °C 0xacb724d3…bf9d
    Sun 2026-10-11 30 °C 30 °C 0x0266fd63…7d1a
    Mon 2026-10-12 30 °C 30 °C 0xc957ccc1…755f
    Tue 2026-10-13 31 °C 31 °C 0xf3e19cbb…1a6b
  • Market maker on Cloudflare (apps/maker-worker, core in packages/maker). Live since 2026-10-08 23:06 UTC as a Cloudflare Worker with a Durable Object, after a 6.5-hour shadow run. It quotes every strike around the Polymarket-implied probability, re-quotes when fair value moves or a side fills, rolls the daily ladder, pulls every quote before close with its kill switch, watches each settlement, tops up the role keys from a treasury within caps, and reads Monad through a fallback across public testnet RPC endpoints.

  • Settlement workflow (packages/cre-workflow). TypeScript compiled to WASM, run hourly at :05 on a small Linux server with the official CRE CLI v1.37.0 (cre workflow simulate --broadcast), delivering through Chainlink's MockKeystoneForwarder with an EIP-712 attestation. Its settlement core (settle-core.ts) is byte-identical to the module validated in spikes/weather (enforced by a test), its METAR rule is the one replayed above, and it is tested on real archive captures. Moving it onto a Chainlink DON is prepared and rehearsed on a fork (DON-CUTOVER.md).

  • Phone app (apps/web). Dynamic email sign-in with an embedded wallet, a test-funds drip, a gasless first deposit, Buy YES / Buy NO / Sell / Merge, a portfolio, redemption, and a Results screen that recovers each settlement's attestation signer in the browser. English and Traditional Chinese.

  • Agent access (packages/mm-plugin). mm weather markets | quote | edge | positions | buy | sell | redeem, plus generic Kuru limit orders. Every write goes through the MetaMask Agent Wallet's signing service and policy.

  • API (apps/api). A Cloudflare Worker with a single-sender Durable Object relayer, served same-origin at /api/*.

Sponsor integrations

Sponsor How Isotherm uses it Onchain proof (Monad testnet)
Kuru One Kuru v1 YES/AUSD order book per strike (16 by 2026-10-10), created through the Kuru Router's deployProxy and validated on chain by the Zap (base, quote, precision, fee cap) Book for ≥ 28 °C created: 0x654807ef…d480; opening maker quotes: 0xb635cafc…c5da
Chainlink CRE Cron-triggered TypeScript workflow, run hourly with the official CRE CLI (cre workflow simulate --broadcast); the Resolver is a CRE IReceiver and accepts EIP-712-attested reports through Chainlink's MockKeystoneForwarder Live Taipei ladders settled by the official CRE CLI v1.37.0 on Monad testnet: 2026-10-08, 28 °C (0x65eee8ef…963d, evidence); 2026-10-09, 29 °C (0xdfd28ea5…3ecd); 2026-10-10, 30 °C (0xacb724d3…bf9d); 2026-10-11, 30 °C (0x0266fd63…7d1a); 2026-10-12, 30 °C (0xc957ccc1…755f); 2026-10-13, 31 °C (0xf3e19cbb…1a6b). Each result equals Polymarket's resolved high; /api/settlements lists every settled day. On 2026-10-07, before the first live settlement, the same CLI settled RCSS + RJTT 2026-10-06 against the v1 contracts on a fork (sim-fork.txt)
Dynamic Email sign-in with an embedded wallet, the default sign-in in the live app; the embedded wallet signs EIP-3009 authorizations for gasless deposits and sends its own trades Recorded flow, 2026-10-09: email sign-in, test-funds drip, gasless YES+NO pair from a signed authorization (0x23fa1a42…650f), then the wallet's own Zap buy (0x120e87a2…09e6) (evidence). First proof, 2026-10-07: 0xca08d015…bf04, 0x361668d8…681c
MetaMask Agent Wallet mm-plugin-isotherm, an oclif plugin for mm 7.x, installed from this repo (setup); writes go through walletExecutor, so MetaMask's signing service and Guard policy see each transaction Signed-in MetaMask Agent Wallet trade in Guard Mode, 2026-10-08: 2 AUSD → 6.054545 YES ≥ 31 °C: 0x82358f48…52ee (evidence)
Agora AUSD The collateral: every YES+NO pair is backed by 1 AUSD. AUSD's EIP-3009 receiveWithAuthorization makes the first deposit gasless AUSD; the gasless deposit above moved 5 AUSD on a signed authorization

Why Monad

  • A real order book for every strike. Kuru is a fully onchain CLOB, so each strike is a book that contracts and agents can read and trade. Opening one costs 1,467,042 gas (about 0.15 testnet MON); a ladder opens up to four of them every day, which only makes sense where blockspace is cheap (gas table).
  • Fast enough for a phone. Blocks average 0.302 s on both Monad mainnet and testnet (1,000-block windows, Oct 11; 0.305 s in the Oct 6 verification), and blocks are final two slots (about 0.6 s) after they land; send-to-receipt had a median of 1,403 ms over the public RPC across a 56-transaction live run (log); the go-live buy in a phone-size browser filled in 1.5 s (go-live).
  • Cheap re-quotes. A live re-quote of one strike (cancel 2 + place 2) billed 0.055–0.058 MON, so the maker can follow the market through the day.
  • Fast payout. Redemption opens 15 minutes after the CRE report, instead of an optimistic-oracle proposal and dispute period.

Contracts and addresses

Source of truth: deployments/testnet.json. v1, deployed 2026-10-07 at block 68,884,377; Solidity 0.8.37. All four are Sourcify exact_match on sourcify-api-monad.blockvision.org and sourcify.dev.

Contract Monad testnet (10143)
Resolver (CRE IReceiver) 0x9c7876Bc27df6cB473f2eaFA296FdEC22747962B
CollateralVault + StrikeFactory 0xae36cf0a163bAfCde4D40a6Ab7b5E3C762ad7B39
IsothermZap 0x1ACaf47987Fe570df5d136Ae1CaC0D45E2B8CFb0
OutcomeToken implementation (each YES/NO is an EIP-1167 clone) 0x5EfaB33DDad0715b66f514Fe12d78Ca23f3e31fC
AUSD (Agora, testnet) · AUSD faucet 0xa9012a055bd4e0eDfF8Ce09f960291C09D5322dC · 0xd236c18D274E54FAccC3dd9DDA4b27965a73ee6C
Kuru v1 Router · MarginAccount 0x7EFbE105Ca7415dE98F96622173458ac1c054630 · 0xd029C2D98ff85D8F64799017fE00a59B1159CE02
CRE MockKeystoneForwarder (active) · KeystoneForwarder 0xB9F79d863261869B234c481D1f9A7af84AeAd192 · 0xF8344CFd5c43616a4366C34E3EEE75af79a74482

Kuru books of the RCSS 2026-10-08 ladder: ≥ 28 0x171b…DBd7, ≥ 29 0x855e…c6c2, ≥ 30 0x702A…36DC, ≥ 31 0x4f5E…5813. Token addresses and seriesIds: docs/OPERATIONS.md.

Repository layout

Stack: Solidity 0.8.37 and Foundry · TypeScript on Node 22 and Bun · a Vite + React + viem PWA · Cloudflare Pages, Workers and Durable Objects · Chainlink CRE (TypeScript compiled to WASM) · Kuru v1 order books · Dynamic SDK · MetaMask Agent Wallet plugin (oclif) · Monad testnet (chain 10143). Architecture: ARCHITECTURE.md.

src/ test/ script/      Solidity contracts, Foundry tests (unit, fuzz, invariant, fork, security), deploy and e2e scripts
deployments/            testnet.json: every address, role and parameter
packages/forecast/      METAR sources, the settlement rule, Polymarket-implied fair values, guardrail model
packages/maker/         Market maker and daily ladder roll
packages/cre-workflow/  Chainlink CRE settlement workflow (TypeScript → WASM)
packages/mm-plugin/     MetaMask Agent Wallet plugin
skills/                 Agent skill for the plugin (isotherm-weather-trading/SKILL.md, same file as packages/mm-plugin/SKILL.md)
packages/abi/           ABIs exported from forge
apps/web/               Phone PWA (Vite + React + viem, Dynamic)
apps/api/               Cloudflare Worker: drip, gasless relayer, snapshot, stats
apps/maker-worker/      The live market maker: Cloudflare Worker + Durable Object
docs/  brand/  spikes/  Runbook and evidence, logo and cover, feasibility spikes from 2026-10-06

Quick start

Requirements: Node 22.18+ (it runs the .ts sources directly) and Foundry. The CRE workflow also needs bun and the CRE CLI v1.37.0, which packages/cre-workflow/setup.sh installs at pinned versions (the CLI download is checksum-verified); the script has pinned builds for macOS and Linux (arm64 and amd64). Keys live outside the repo (~/.config/isotherm/, one file per role); never commit them.

forge build && forge test                                                       # offline suite (fork tests skip)
MONAD_TESTNET_RPC=https://testnet-rpc.monad.xyz FORK_BLOCK=68898133 forge test  # full suite: 149 tests in 18 suites
(cd packages/forecast && npm test && npm run settle -- RCSS 2026-10-04 2026-10-05)   # recompute days from public archives
(cd packages/maker && npm ci && npm test)
(cd packages/maker && node src/cli.ts preflight --station RCSS --date tomorrow)   # operator command: read-only, needs the maker key file
(cd apps/web && npm ci && npm test && npm run dev)                 # http://127.0.0.1:5173
(cd apps/api && npm ci && npm test)                                # npm run test:fork: anvil-fork integration tests
(cd packages/mm-plugin && npm ci && npm run build && npm test)
cd packages/cre-workflow && ./setup.sh && export PATH="$PWD/.tools/bin:$PWD/.tools/node_modules/.bin:$PATH"
(cd settle && bun test && bun run build)                           # unit + golden tests, WASM build

Deployment (script/deploy-testnet.sh, testnet only), the live maker, the API and the settlement job are documented in docs/OPERATIONS.md and each package's README.

Disclosures

Built with AI coding tools: Claude Code (Anthropic). Ted Chen chose the idea, directed the work and made the product decisions; Claude Code wrote most of the code, tests, scripts, documentation and the logo under that direction. Every commit made with Claude Code carries a Co-Authored-By: Claude trailer. The narration in the videos is a synthetic voice generated with VoxCPM2 (OpenBMB, Apache-2.0); no real person's voice was recorded or cloned.

Originality and pre-existing code. Isotherm's own code was all written during the Metropolis build window (Sep 1 – Oct 13, 2026); the first commit is dated 2026-10-06 and the commit history covers the build. No pre-existing code from earlier projects is included. The only code we did not write is the third-party software below. Isotherm builds on existing products and protocols, used as integrations: Monad testnet, Kuru v1 order books, Chainlink CRE, Dynamic, the MetaMask Agent Wallet and Agora AUSD (testnet), plus public Polymarket and weather data (below). The logo and video cover in brand/ are original artwork made for this project.

Third-party code

Summary in NOTICE.md; each component keeps its own license.

Component License Use
OpenZeppelin Contracts 5.7.0 MIT Vendored in lib/: ERC-20, EIP-2612, EIP-712, clones, SafeERC20, reentrancy guard
forge-std 1.17.0 MIT or Apache-2.0 Tests and scripts
Kuru v1 interfaces (Kuru-Labs/Kuru-contracts-dex-public, commit 2060bb2) GPL-2.0-or-later src/interfaces/IKuru.sol, spikes/kuru/src/interfaces/IKuru.sol and spikes/e2e/src/IsothermZap.sol are derived from Kuru's public interfaces and carry GPL-2.0-or-later headers. src/IsothermZap.sol (MIT) imports that interface, so the compiled IsothermZap is distributed under GPL-2.0-or-later terms; text in LICENSES/GPL-2.0-or-later.txt.
Chainlink CRE TypeScript SDK 1.23.0 BUSL-1.1 npm dependency of the workflow
Chainlink CRE CLI v1.37.0; KeystoneForwarder, MockKeystoneForwarder and the IReceiver interface MIT Build and run the workflow; the forwarders are called onchain; src/interfaces/IReceiver.sol reproduces Chainlink's published IReceiver interface
Dynamic SDK (@dynamic-labs/* 5.9.4, @dynamic-labs-sdk/* 1.38.0) MIT (@dynamic-labs-sdk/*: Dynamic's terms) Login and embedded wallet
MetaMask Agent Wallet @metamask/agent-wallet 7.x MetaMask source-available license Peer dependency of the plugin, not redistributed
viem, @noble/curves, oclif, React, Vite, zod MIT Libraries

Data sources

Attribution and terms for committed data are in DATA-NOTICE.md.

Source Used for Terms
Iowa Environmental Mesonet (Iowa State University) Settlement source A, history Free public archive; cached, low request rates
aviationweather.gov (NOAA / NWS Aviation Weather Center) Settlement source B U.S. government data; API usage limits observed
Ogimet Settlement fallback Queried gently, at most once per workflow run
Open-Meteo Guardrail forecast model, shown as "Model" in the app Weather data by Open-Meteo.com, CC BY 4.0; values are bias-corrected and combined (modified). Free API for non-commercial use
Polymarket public Gamma and CLOB APIs Reference fair value; fidelity check Read-only public market data under Polymarket's Terms of Use; Isotherm is not affiliated with Polymarket

License

MIT, see LICENSE. Files derived from Kuru's public contracts and the compiled IsothermZap are GPL-2.0-or-later as described above; third-party code and data keep their own terms (NOTICE.md, DATA-NOTICE.md).

Built by Ted Chen.

About

Isotherm — daily city-temperature strike ladders on Monad: YES/NO tokens on Kuru order books, settled by Chainlink CRE from airport METAR. Monad Metropolis hackathon (testnet).

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages