Strategy · Early Developer Footprint

The developer who ships thechain-native primitive first.

I'm pplmaverick, an independent Web3 developer. The strategy is simple: the moment a new chain or L1/L2 opens a testnet, I ship a contract that actually uses that chain's unique native feature — not another copy-pasted ERC-20, but things like Midnight's ZK witnesses, Fhenix's FHE-encrypted types, or Ritual's on-chain HTTP precompile — primitives that only exist on that one chain. This site is the record of that footprint: 11 chains, 11 projects, 8 of them already live with a working, interactive frontend.

11Chains
11Projects
8Live deployments
MBA M3 · iMac M1 · HetznerDev setup

Projects

Each card is one chain, one native primitive, one set of deployed contracts.

Midnight
Live — Mainnet
Midnight Private Auction
Sealed-bid auction — bid amounts stay hidden until reveal, then disclosed on-chain via commit-reveal.

Compact witnesses + commit-reveal ZK

Bids are hashed client-side (secret key, amount, salt) inside a Compact circuit into a single commitment; disclose() only publishes the amount at reveal time.

React frontendin-browser ZK proving
Compact contractMidnight ledger
Indexer GraphQLpublic reads

No external oracle — all state sourced from the Midnight ledger/indexer.

Auction Contract4fd31443…3282e5
Compact 0.23midnight-js SDKReact 19ViteTailwind 4

Architecture

Bidder — private witnesses

never leaves device

localSecretKey(): Bytes<32>
myBidAmount(auctionId): Uint<32>
myBidSalt(auctionId): Bytes<32>
ZK proof

Midnight ledger

sealedBids: Map<Uint, Map<Bytes, Bytes>>

sealedBids[auctionId][bidderPK]
= persistentHash("auction:seal:",
sk, auctionId, amount, salt)
Chain observers see: bidderPK + sealed hash. Cannot see: amount · salt · secretKey.
REVEAL PHASE — after closeAuction()

Bidder discloses

revealBid(auctionId, amount, salt)

amount = disclose(amount)
ZK verify

Ledger verifies & updates

assert computeCommitment(sk, auctionId,
amount, salt) == sealedBids[id][pk]
if amount > highestBid:
highestBid = amount
highestBidderPK = pk
sk stays local — only a ZK proof is submitted, never sk
Multi-auction architecture: one contract, many concurrent auctions, each with isolated bidCount / highestBid / highestBidderPK.
Compact languagepersistentHash (built-in)@midnight-ntwrk/wallet-sdk-facadeMainnet ✓
Fhenix (CoFHE)
Live — Testnet (Arbitrum Sepolia)
Fhenix Confidential Prediction Market
Prediction market where bet size and side stay encrypted end-to-end.

FHE euint64 / ebool via CoFHE coprocessor

Client-encrypted InEuint64/InEbool inputs are combined on-chain with FHE.select/FHE.eq, settled via the CoFHE threshold network's publishDecryptResult signature.

React + cofhe-sdklocal encryption
ConfidentialPredictionMarket.solArbitrum Sepolia
CoFHE threshold networkoff-chain decrypt

No price oracle yet — outcomes submitted manually by market owner (Chainlink integration on roadmap).

ConfidentialPredictionMarket0x9DE6ba…55138d
MarketFactory0x575FF2…8482FA
Solidity 0.8.28CoFHE / FHE.solHardhat 2Reactwagmi

Architecture

PLACE BET

cofheClient (browser)

@cofhe/sdk

encryptInputs([
Encryptable.uint64(amountWei),
Encryptable.bool(choice)])
InEuint64 / InEbool

ConfidentialPredictionMarket.sol

placeBet(marketId, InEuint64, InEbool)

euint64 encAmount; ebool encChoice;
FHE.allowThis / FHE.allowSender
encAmount (euint64) and msg.value (uint256) are tracked as two separate ledgers — the contract never checks they match. A single bet above ~18.44 ETH worth of wei overflows euint64, desyncing the encrypted payout math from the real market.totalPool.
SETTLE — reveal & claim

revealWinnerPool() / claimWinnings()

FHE.eq(encChoice, outcomeEnc)
FHE.select(isWinner, encAmount, 0)
ctHash

CoFHE threshold network

off-chain signers

decryptForTx(ctHash)
→ { decryptedValue, signature }
signature

submitWinnerPool() / withdraw()

FHE.publishDecryptResult(
ctHash, value, signature)
No price oracle yet — outcome set manually via submitResult(); Chainlink integration is on the roadmap.
Solidity 0.8.28FHE.sol (euint64 / ebool)@cofhe/sdkArbitrum Sepolia
Aztec
Live — Mainnet
Aztec Private Voting
Cast a vote that proves validity without revealing choice or voter identity.

Noir ZK circuits + nullifier-based privacy

A Noir circuit proves cast_vote() validity client-side; a SingleUseClaim nullifier blocks double-voting while the choice itself never leaves the device.

Noir circuitclient-side proof
cast_vote + nullifierprivate call
Public tallyPublicMutable map

11/11 contract tests passing. Deployed first to Aztec Testnet, then to Alpha Mainnet (v5.0.1, post AZUP-2) with a full create_poll/cast_vote/end_poll e2e run verified on-chain. React frontend in progress.

PrivateVoting0x25bb47…a3e38e
Noir 1.0.0-beta.22aztec-nr v5.0.0Barretenberg (UltraHonk)

Architecture

CAST VOTE — #[external("private")]

cast_vote(poll_id, choice)

choice never leaves this call

vote_claims.at(poll_id)
.at(msg_sender()).claim()
→ app-siloed nullifier
enqueue_self

add_to_tally_public(poll_id, choice)

#[external("public")] #[only_self]

tally: Map<PollId,
Map<Field, PublicMutable<Field>>>
tally[poll][choice] += 1
Double-voting is blocked at the nullifier: reusing a claim fails with "duplicate siloed nullifier" — proven in voting_tests.nr.
Noir 1.0.0-beta.22aztec-nr v5.0.0Barretenberg (UltraHonk)Aztec Alpha Mainnet
RepoNo frontend yet
Arc (Circle)
Live — Testnet
Presage
Presage — On-chain prediction markets, built on Arc. Weather is just the beginning.

Native USDC precompile + ERC-8004 agent

Bets settle in USDC via Arc's native precompile (no bridging/wrapping); a separately registered ERC-8004 agent identity (id 6762) exists as off-chain metadata — WeatherMarket.sol has no on-chain dependency on it.

React + wagmiplace bet in USDC
WeatherMarket.solArc testnet
n8n oracleOpenWeather API

Self-hosted n8n workflow locks the market then submits the result through AdminOracle (onlyOracle-gated); decentralized oracle is on the roadmap.

WeatherMarket0xcac5b9…9cf953
USDC (native precompile)0x360000…000000
Solidity 0.8.28OpenZeppelin 5Hardhat 3Reactwagmin8n

Architecture

PLACE BET

WeatherMarket.sol

placeBet(marketId, bucket, amount)

usdc.transferFrom(sender, this, amount)
native USDC precompile — no wrapping
SETTLE — two-stage oracle, n8n-triggered

lockMarket(marketId)

callable by anyone, after lockTime

Status: OPEN -> LOCKED
n8n: stage 1 -> stage 2

AdminOracle.submitResult(city, temp, id)

onlyOwner

-> WeatherMarket.submitResult(id, temp)
onlyOracle-gated

claimWinnings(marketId)

payout = amount * netPool / bucketTotal
FEE_BPS = 200 (2%), waived if noWinner
Solidity 0.8.28OpenZeppelin 5Native USDC (no wrap)Arc Testnet
Tempo
Live — Mainnet + Testnet
Tempo Weather Market
Weather market built on Stripe's payments-native chain, gas-sponsored for bettors.

Payment Memo + Fee Sponsorship + Scheduled Transactions

Settlement writes a structured Payment Memo on-chain, bettors never hold gas thanks to Tempo's Fee Sponsorship relayers, and markets auto-lock via the native Scheduler precompile.

React + wagmipathUSD / USDC.e bets
WeatherMarket.solTempo scheduled lock
Express oracle serverOpenWeather + median

n8n triggers the oracle server's /oracle/settle after lockTime; server signs and submits the result on-chain.

WeatherMarket (Mainnet, 4217)0x072a3a…41531f
WeatherMarket (Moderato Testnet, 42431)0xcAC5B9…9cF953
Solidity 0.8.28Hardhat 3React 19wagmi/viemNode.js oracle server

Architecture

PLACE BET — fee-sponsored

placeBet(...) / placeBetFor(..., bettor)

placeBetFor is onlyRelayer

approvedRelayers[msg.sender]
gasTankBalance funds relayer gas
bettor pays zero gas via placeBetFor
SCHEDULED LOCK

createMarket(...)

native Scheduler precompile

IScheduler(scheduler).schedule(
address(this), lockCallData, lockTime)
scheduled taskId

lockMarket(marketId)

auto-fires at lockTime

m.lockTaskId = taskId
SETTLE — oracle server

POST /oracle/settle

Node/Express oracle-server

getMaxTempWithSources(city, date)
determineOutcome() -> WIN / NO_WINNER
submitResult()

WeatherMarket.submitResult(id, temp, memo)

memo = "{city}/{type}/{temp}/{outcome}"
stored as Market.settleMemo, emitted
Tempo's 0x76 transaction type is viem's fee-token serializer for gas-in-USDC.e mainnet txs — it belongs to Fee Sponsorship, not the Scheduler.
Solidity 0.8.28IScheduler precompileFee Sponsorship (gasTank)Mainnet + Testnet
Miden
Live — Testnet
Miden Weather Market
Weather bets on a STARK rollup — client-side bet commitments, CLI-assisted proving. Oracle signature verification — planned (Miden rpo_falcon512 roadmap).

Client-side ZK commitments + Poseidon2 hashing

Bet commitments are Poseidon2 hashes computed in-browser WASM, keeping the user's secret local to the device. Oracle signature verification via rpo_falcon512 is planned for a future milestone.

React + in-browser WASMPoseidon2 commitment
Miden account (StorageMap)MASM contract
Python oracle (VPS)Falcon512-signed weather data

Automated oracle → settle_market pipeline not yet wired end-to-end; settlement is CLI-triggered today.

WeatherMarket Account (v7)0x72df3f…1422af
Rust → wasm32-wasip2MASMReact 19@miden-sdk/miden-sdkPython oracle

Architecture

PLACE BET — client-side commitment

Browser WASM

@miden-sdk/miden-sdk

Poseidon2.hashElements([
marketId, outcome, amount, userSecret])
commitment (Word)

bets: StorageMap<Word, Felt>

place_bet(...)

bets[commitment] = amount
userSecret never leaves the device — only the commitment is sent
SETTLE — time-lock, not signature

settle_market(...)

assert status == STATUS_OPEN
assert close_time <= now
README describes a Falcon512 oracle-signature check ("M1.5 — completed"), but the deployed settle_market() has no signature verification — Miden 0.15's rpo_falcon512_verify only verifies the signature over the tx commitment, not arbitrary messages. Current trust = wallet-key holder + on-chain time-lock only.
Rust → wasm32-wasip2MASMPoseidon2 (RPO)Testnet
Pharos
Live — Mainnet + Testnet
Pharos Weather Market
High-throughput weather market on Pharos — CCIP oracle and CCTP bridging are deployed but not yet wired live.

Native USDC settlement + CCIP/CCTP (deployed, not yet live)

Bets settle directly in USDC on Pharos. A CCIPWeatherOracle contract and an Arc-to-Pharos CCTP bridge script both exist in the repo, but the live settlement path still runs through the same single-owner AdminOracle used on testnet, and the frontend's bridge page is a disabled placeholder.

React + wagminative USDC bets
WeatherMarket.solPharos testnet + mainnet
AdminOraclesingle-owner (the live path)

CCIPWeatherOracle and the CCTP bridge are deployed on mainnet but not wired into WeatherMarket.oracle yet — the settlement path actually in use is the same admin-gated oracle as testnet.

WeatherMarket (Mainnet, 1672)0xcac5b9…9cf953
CCIPWeatherOracle (Mainnet)0x914c40…06c68d
WeatherMarket (Atlantic Testnet, 688689)0x072a3a…41531f
Solidity 0.8.28OpenZeppelin 5Hardhat 3React 18wagmi 2 / viem 2

Architecture

PLACE BET — native USDC

placeBet(marketId, bucket, amount)

usdc.transferFrom(sender, this, amount)
chain 1672 (mainnet) / 688689 (testnet)
SETTLE — the path actually live

lockMarket() -> AdminOracle.submitResult(...)

onlyOwner — same as testnet

-> WeatherMarket.submitResult(id, temp)
CCIPWeatherOracle.sol and the Arc-to-Pharos CCTP bridge are both deployed but not wired live: WeatherMarket.oracle still points at AdminOracle, and the frontend's bridge page is a disabled "Coming Soon" stub. The sub-second-finality and cross-chain-CCIP claims in the README aren't yet reflected in what's actually connected on-chain.
Solidity 0.8.28AggregatorV3-style oracleCCIP + CCTP (deployed, not wired)Testnet + Mainnet
Seismic
Contracts only — CLI, no frontend yet
Seismic Spread Monitor
Privacy-preserving spread alert contract using Seismic's shielded EVM types.

Shielded types: suint256 / saddress

Trading-pair identifier and alert threshold are stored as encrypted saddress/suint256; checkSpread() compares an input spread against the private threshold inside Seismic's encrypted VM.

CLI (scast signed calls)seismic-viem planned
SpreadMonitor.solencrypted VM compare

No live price feed yet — checkSpread() takes a manually supplied value; README documents a known side-channel limitation.

SpreadMonitor0xBdC53E…741051
Seismic Solidity ^0.8.13sFoundry (sforge/scast)

Architecture

SET STRATEGY — shielded state

setStrategy(saddress pair, suint256 threshold)

struct Strategy { saddress pair;
suint256 threshold; bool isActive; }
CHECK SPREAD — encrypted VM compare

checkSpread(suint256 currentSpread)

bool triggered =
bool(currentSpread >= threshold)
emits

event SpreadAlert(user, triggered)

only event in the contract
README's own Known Limitations: the public currentSpread input plus the public triggered event let an observer binary-search the private threshold — a real side-channel, not yet fixed.
Seismic Solidity ^0.8.13sFoundry (sforge / scast)CLI only, no frontendTestnet
RepoNo frontend yet
Ritual
Live — Testnet
Ritual Weather Market
Weather market that calls the OpenWeather API directly from Solidity, no oracle bot.

TEE HTTP precompile (0x0801) + ERC-8004 identity

resolveMarket() calls Ritual's HTTP precompile directly; a TEE node selected from TEEServiceRegistry fetches the real HTTPS response, which replays on-chain via Ritual's SPC execution model.

Next.js + RainbowKitwagmi + viem
WeatherMarket.solTEEServiceRegistry
HTTP precompile 0x0801OpenWeather, in-protocol

No off-chain oracle bot — the TEE executor fetches live HTTPS data as part of Ritual's own execution pipeline.

WeatherMarket0x072A3A…41531f
IdentityRegistry (ERC-8004)0x4fcee9…b0d75b
Solidity ^0.8.20FoundryNext.js 14wagmi 2RainbowKit 2

Architecture

resolveMarket() — HTTP call, on-chain

resolveMarket(marketId)

require !resolved
require block.timestamp >= resolutionTime
pickServiceByCapability

TEEServiceRegistry

pickServiceByCapability(
HTTP_CALL=0) → executor
HTTP_PRECOMPILE.call()

0x…0801 precompile

Ritual SPC model

1st call: empty output, returns early
TEE fetches OpenWeather off-chain
replay: decode statusCode / body
SETTLE

Settle & emit

actualTemp = _parseTemp(body)
resultIsAbove = actualTemp > targetTemp
emit MarketResolved(...)
ERC-8004 IdentityRegistry is deployed standalone — WeatherMarket.sol has zero references to it; the link is off-chain metadata only.
Solidity ^0.8.20Foundry (26/26 tests)Next.js 14 + RainbowKitRitual Testnet
Robinhood Chain
Live — Mainnet (since 2026-07-03)
Robinhood Chain Prediction Market
Prediction markets bound directly to Robinhood Chain's native tokenized stock tokens.

Native tokenized equity tokens (TSLA, AMZN, PLTR, AMD, NVDA)

createMarket() binds each market directly to the on-chain address of a Robinhood Chain tokenized stock; settlement reads Chainlink price feed wrappers mirroring AggregatorV3Interface.

React + wagmiBULL / BEAR pools
StockPredictionMarket.solbound to stock token
Chainlink price feedAggregatorV3Interface

Parimutuel settlement minus a 2% fee, with a 3-day staleness tolerance on the price feed for market closures.

StockPredictionMarket0x72DAb8…264245
Solidity ^0.8.20Hardhat 2ethers.jsReact 18wagmi 2 / viem

Architecture

CREATE MARKET — bound to native stock token

createMarket(stockToken, priceFeed, symbol, duration)

Market.stockToken = native tokenized equity
e.g. TSLA / AMZN / PLTR / AMD / NVDA
LOCK / SETTLE — Chainlink price feed

ChainlinkPriceFeed.latestRoundData()

wraps AggregatorV3Interface

require(answer > 0)
require(block.timestamp - updatedAt
<= 3 days)
latestRoundData()

lockMarket() / settleMarket()

openPrice / closePrice snapshotted
winner = closePrice >= openPrice ? BULL : BEAR
CLAIM — parimutuel

claimWinnings()

fee = totalPool * 200 / 10000 (2%)
payout = (totalPool - fee) * bet / winnerPool
Solidity ^0.8.20AggregatorV3InterfaceRobinhood Chain Mainnet5 stock markets live
Linera
Contracts only — single-chain prototype, no frontend
Linera Price Market
Price market on Linera — the microchains cross-chain design is the roadmap, not what's deployed today.

Single-chain price market (microchains architecture planned)

CreateRound/PlaceBet/ResolveRound/Claim all run on one chain today. The README's user-microchain-to-market-microchain messaging design is the intended architecture, but the deployed contract sets Message = () and execute_message() panics — there is no cross-chain messaging yet.

CLI / GraphQL servicelinera service --port 8080
PriceMarket contractsingle chain today

Cross-chain microchain messaging, emit_event!, and the payout-message flow are described in the README as the intended design but aren't implemented in contract.rs yet — Message = () and execute_message() panics. CoinGecko calls are also blocked by Conway testnet's http_request_allow_list, so prices are fed in by an external bot via ResolveRound.

Application IDa788ba8f…8b6a1c
Rust → wasm32-unknown-unknownlinera-sdk 0.15async-graphql

Architecture

OPERATIONS — single chain today

Operation enum

CreateRound { asset,
duration_secs, start_price }
PlaceBet { round_id,
direction, amount }
ResolveRound { round_id, final_price }
Claim { round_id }

PriceMarket state

rounds: MapView<u64, Round>
Round { bets: Vec<Bet>,
status, deadline }
README describes a microchains architecture — a user's single-owner chain sending a cross-chain PlaceBet message to a shared market chain, with a payout message flowing back — but the deployed contract sets Message = () and execute_message() panics with "PriceMarket does not support cross-chain messages". There's no emit_event! call either. This is a single-chain prototype today, not the microchains design described in the README.
Rust → wasm32-unknown-unknownlinera-sdk 0.15Single-chain (microchains planned)Testnet (Conway)
RepoNo frontend yet