StabilityNet is prototype that monitors real on-chain signals and publishes a single Instability Index (0–100) on-chain. When the index crosses a danger threshold (>= 75), an Immune System contract can activate defensive controls.
Repo layout:
stabilitynet-contracts/— Solidity smart contracts (Foundry)detection/— detection + scoring + publish CLI (TypeScript)frontend/— dashboard UI (Next.js + wagmi + viem)
- Collect signals from Sepolia using RPC (no backend):
- Liquidity Drop (Uniswap V2 pair reserves)
- Whale Transfers (ERC20 Transfer events)
- Flash Loan Events (FlashLoan event counter)
- DAO Vote Split (Governor VoteCast events)
- Compute risk categories and a final index:
- Economic risk (0–40)
- Social risk (0–30)
- Governance risk (0–30)
instabilityIndex = economic + social + governance(0–100)
- Publish score to the on-chain Oracle:
publishScore(uint256 score)
- On-chain reaction (contracts):
- Oracle stores latest values + emits
StabilityAlert - If score >= 75 and immune system is configured, Oracle can trigger ImmuneSystem defenses
- Oracle stores latest values + emits
Located in stabilitynet-contracts/contracts/.
- Permissioned publisher (allowed source)
- Accepts
publishScore(uint256 score)wherescore <= 100 - Maintains latest score and timestamps
- Emits alerts (events)
- Can call the Immune System when danger threshold is met
Useful public getters (Solidity public variables compile into getters):
lastScore() -> uint256(used as "global index" in the UI)lastUpdated() -> uint256allowedSource() -> addressimmuneSystem() -> address
Provides defensive "immune" states exposed to the UI:
isCooldownActive() -> boolisGuardrailActive() -> bool
- CLI analysis (
npm run analyze): fetch signals + compute risk breakdown + final index - CLI publish (
npm run publish): analyze +publishScore(index)on the Oracle - Optional authorization helper (
npm run authorize) for permissioned Oracle
- Install:
npm --prefix ./detection install- Configure:
- Edit
detection/config/config.jsonrpcUrl(Sepolia RPC)- addresses for monitored contracts (pair/token/governor/etc)
oracle.address(Oracle deployed address)
- Run analysis:
npm --prefix ./detection run analyze- Publish a score (permissioned):
- Set env var
PUBLISHER_PRIVATE_KEY(32-byte hex)
# bash example
export PUBLISHER_PRIVATE_KEY=0x...
npm --prefix ./detection run publishIf Oracle restricts publishing, the Oracle owner must set the allowed publisher:
- Env vars:
ORACLE_OWNER_PRIVATE_KEY(owner/deployer key)PUBLISHER_ADDRESS(address to allowlist) ORPUBLISHER_PRIVATE_KEY
- Run:
npm --prefix ./detection run authorize- Dashboard (global index + alerts)
- Signals page (shows outputs from Person 2 analysis)
- Immune System page (cooldown + guardrail + alerts)
- Publish Score page (Analyze Chain + Publish Score)
- Install:
npm --prefix ./frontend install- Environment variables
Create
frontend/.env.local:
# RPC for browser reads (public RPC is recommended for CORS reliability)
NEXT_PUBLIC_SEPOLIA_RPC_URL=https://ethereum-sepolia-rpc.publicnode.com
# Optional (may be rate-limited / CORS blocked in browsers)
NEXT_PUBLIC_ALCHEMY_API_KEY=YOUR_ALCHEMY_KEY
# Deployed contract addresses (Sepolia)
NEXT_PUBLIC_STABILITY_ORACLE_ADDRESS=0x...
NEXT_PUBLIC_IMMUNE_SYSTEM_ADDRESS=0x...
- Run dev server:
npm --prefix ./frontend run devThe UI publishes from the connected wallet. If the Oracle is permissioned:
- the connected wallet address must be allowlisted by the Oracle owner (
setAllowedSource).
- Start frontend and connect wallet.
- Go to
/publish-score. - Click Analyze Chain to compute the index from real signals.
- Click Publish Score to write the index on-chain.
- Check
/dashboardand/immunefor:- updated global index (
lastScore()) StabilityAlertevents- immune system status
- updated global index (
Update these if you redeploy.
- StabilityOracle:
0xd18Ad0acCeC2F1f6DE67B08c1eD88164840af6C7 - ImmuneSystem:
0xD53f40B0C59c8C9908d9b205BfE564B60fBdfc0e
- UI shows index but Analyze Chain is 0: there may be no qualifying events in the current block window for the configured contracts.
- Analyze Chain shows 400/429/CORS: switch to a public RPC using
NEXT_PUBLIC_SEPOLIA_RPC_URL. - Publish fails/reverts: likely the connected wallet is not allowlisted (permissioned oracle) or lacks Sepolia ETH for gas.
- Never commit private keys (
PUBLISHER_PRIVATE_KEY,ORACLE_OWNER_PRIVATE_KEY). - Use test wallets on Sepolia only.
- ....