diff --git a/drosera-trap-simulator/README.md b/drosera-trap-simulator/README.md
new file mode 100644
index 0000000..c8fb35d
--- /dev/null
+++ b/drosera-trap-simulator/README.md
@@ -0,0 +1,13 @@
+# Drosera Trap Simulator
+
+A simple UI to simulate, test, and visualize Drosera Trap logic.
+
+### ๐ง Features
+- Write custom trap logic
+- Simulate test events
+- View real-time results
+- Leaderboard with active trap deployers (Proof-of-Trap โ Cadet)
+
+Built with **Vite + React + TailwindCSS**.
+
+> ๐งช Deployed version: [https://drosera-gamma.vercel.app](https://drosera-gamma.vercel.app/)
diff --git a/drosera-trap-simulator/drosera-logo.png b/drosera-trap-simulator/drosera-logo.png
new file mode 100644
index 0000000..a126364
Binary files /dev/null and b/drosera-trap-simulator/drosera-logo.png differ
diff --git a/drosera-trap-simulator/drosera.png b/drosera-trap-simulator/drosera.png
new file mode 100644
index 0000000..469b525
Binary files /dev/null and b/drosera-trap-simulator/drosera.png differ
diff --git a/drosera-trap-simulator/eslint.config.js b/drosera-trap-simulator/eslint.config.js
new file mode 100644
index 0000000..092408a
--- /dev/null
+++ b/drosera-trap-simulator/eslint.config.js
@@ -0,0 +1,28 @@
+import js from '@eslint/js'
+import globals from 'globals'
+import reactHooks from 'eslint-plugin-react-hooks'
+import reactRefresh from 'eslint-plugin-react-refresh'
+import tseslint from 'typescript-eslint'
+
+export default tseslint.config(
+ { ignores: ['dist'] },
+ {
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
+ files: ['**/*.{ts,tsx}'],
+ languageOptions: {
+ ecmaVersion: 2020,
+ globals: globals.browser,
+ },
+ plugins: {
+ 'react-hooks': reactHooks,
+ 'react-refresh': reactRefresh,
+ },
+ rules: {
+ ...reactHooks.configs.recommended.rules,
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ },
+ },
+)
diff --git a/drosera-trap-simulator/index.html b/drosera-trap-simulator/index.html
new file mode 100644
index 0000000..55c027e
--- /dev/null
+++ b/drosera-trap-simulator/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Drosera Simulator
+
+
+
+
+
+
diff --git a/drosera-trap-simulator/package.json b/drosera-trap-simulator/package.json
new file mode 100644
index 0000000..637584b
--- /dev/null
+++ b/drosera-trap-simulator/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "drosera-trap-simulator",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "lint": "eslint .",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@monaco-editor/react": "^4.7.0",
+ "ethers": "^6.14.3",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.25.0",
+ "@tailwindcss/postcss": "^4.1.8",
+ "@types/react": "^19.1.2",
+ "@types/react-dom": "^19.1.2",
+ "@vitejs/plugin-react": "^4.4.1",
+ "autoprefixer": "^10.4.21",
+ "eslint": "^9.25.0",
+ "eslint-plugin-react-hooks": "^5.2.0",
+ "eslint-plugin-react-refresh": "^0.4.19",
+ "globals": "^16.0.0",
+ "postcss": "^8.5.4",
+ "tailwindcss": "^3.4.1",
+ "typescript": "~5.8.3",
+ "typescript-eslint": "^8.30.1",
+ "vite": "^6.3.5"
+ }
+}
diff --git a/drosera-trap-simulator/postcss.config.cjs b/drosera-trap-simulator/postcss.config.cjs
new file mode 100644
index 0000000..a03e681
--- /dev/null
+++ b/drosera-trap-simulator/postcss.config.cjs
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/drosera-trap-simulator/public/drosera-logo.png b/drosera-trap-simulator/public/drosera-logo.png
new file mode 100644
index 0000000..a126364
Binary files /dev/null and b/drosera-trap-simulator/public/drosera-logo.png differ
diff --git a/drosera-trap-simulator/public/vite.svg b/drosera-trap-simulator/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/drosera-trap-simulator/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/drosera-trap-simulator/src/App.css b/drosera-trap-simulator/src/App.css
new file mode 100644
index 0000000..b9d355d
--- /dev/null
+++ b/drosera-trap-simulator/src/App.css
@@ -0,0 +1,42 @@
+#root {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+ transition: filter 300ms;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+ filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ a:nth-of-type(2) .logo {
+ animation: logo-spin infinite 20s linear;
+ }
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
diff --git a/drosera-trap-simulator/src/App.tsx b/drosera-trap-simulator/src/App.tsx
new file mode 100644
index 0000000..52130f4
--- /dev/null
+++ b/drosera-trap-simulator/src/App.tsx
@@ -0,0 +1,235 @@
+// Drosera Trap Simulator with Tabs for LiveBoard
+import React, { useState, useRef } from 'react';
+import Editor from '@monaco-editor/react';
+import './index.css';
+import LiveBoard from './LiveBoard';
+
+function App() {
+ const trapPresets = [
+ {
+ label: "๐จ Bridge Exploit",
+ logic: `async function trap(event) {
+ if (event.type === "bridge" && event.amount > 100000 && event.to === "0xdeadbeef") {
+ return "๐จ Potential bridge exploit!";
+ }
+}`,
+ event: `{
+ "type": "bridge",
+ "amount": 150000,
+ "to": "0xdeadbeef",
+ "timestamp": ${Date.now()}
+}`
+ },
+ {
+ label: "๐ ETH High Slippage",
+ logic: `async function trap(event) {
+ if (event.token === "ETH" && event.amount > 1000 && event.slippage > 5) {
+ return "๐ Large ETH swap with high slippage!";
+ }
+}`,
+ event: `{
+ "type": "swap",
+ "token": "ETH",
+ "amount": 1200,
+ "slippage": 7,
+ "timestamp": ${Date.now()}
+}`
+ },
+ {
+ label: "๐ Off-Hour Transaction",
+ logic: `async function trap(event) {
+ const hour = new Date(event.timestamp).getUTCHours();
+ if (hour >= 0 && hour <= 3 && event.amount > 10000) {
+ return "๐ Suspicious large txn during off-hours!";
+ }
+}`,
+ event: `{
+ "amount": 12000,
+ "timestamp": ${(() => {
+ const d = new Date();
+ d.setUTCHours(Math.floor(Math.random() * 4), 0, 0, 0);
+ return d.getTime();
+ })()}
+}`
+ },
+ {
+ label: "๐ Oracle Price Drop",
+ logic: `async function trap(event) {
+ if (event.asset === "BTC" && event.oraclePrice < 20000) {
+ return "๐ Oracle price dropped significantly!";
+ }
+}`,
+ event: `{
+ "type": "oracle",
+ "asset": "BTC",
+ "oraclePrice": 19500,
+ "timestamp": ${Date.now()}
+}`
+ },
+ {
+ label: "โ๏ธ AVS Slashing",
+ logic: `async function trap(event) {
+ if (event.avs === "staking" && event.slashAmount > 5000) {
+ return "โ๏ธ AVS slashing triggered!";
+ }
+}`,
+ event: `{
+ "type": "slashing",
+ "avs": "staking",
+ "slashAmount": 6000,
+ "timestamp": ${Date.now()}
+}`
+ },
+ {
+ label: "๐ DEX Liquidity Drop",
+ logic: `async function trap(event) {
+ if (event.pool === "DEX-XYZ" && event.liquidityUSD < 1000000) {
+ return "๐ Liquidity has dropped dangerously low on DEX!";
+ }
+}`,
+ event: `{
+ "type": "liquidity",
+ "pool": "DEX-XYZ",
+ "liquidityUSD": 800000,
+ "timestamp": ${Date.now()}
+}`
+ },
+ {
+ label: "๐ฆ Lending Collateral Event",
+ logic: `async function trap(event) {
+ if (event.collateralRatio < 1.2 && event.loanId) {
+ return "๐ฆ Lending collateral ratio below threshold!";
+ }
+}`,
+ event: `{
+ "type": "loan",
+ "loanId": "LN-1234",
+ "collateralRatio": 1.1,
+ "timestamp": ${Date.now()}
+}`
+ }
+ ];
+
+ const presetIndexRef = useRef(0);
+ const [trapLogic, setTrapLogic] = useState(trapPresets[0].logic);
+ const [simulatedEvent, setSimulatedEvent] = useState(trapPresets[0].event);
+ const [output, setOutput] = useState<{ triggered: boolean; message: string } | null>(null);
+ const [activeTab, setActiveTab] = useState<'simulator' | 'liveboard'>('simulator');
+
+ const handleRunTrap = async () => {
+ try {
+ const event = JSON.parse(simulatedEvent);
+ const fullCode = `(async () => { ${trapLogic}; return await trap(${JSON.stringify(event)}); })()`;
+ const result = await eval(fullCode);
+
+ if (result) {
+ setOutput({ triggered: true, message: result });
+ } else {
+ setOutput({ triggered: false, message: "Trap NOT TRIGGERED" });
+ }
+ } catch (error: any) {
+ setOutput({ triggered: false, message: `Error: ${error.message}` });
+ }
+ };
+
+ const generateTrapAndEvent = () => {
+ presetIndexRef.current = (presetIndexRef.current + 1) % trapPresets.length;
+ const preset = trapPresets[presetIndexRef.current];
+ setTrapLogic(preset.logic);
+ setSimulatedEvent(preset.event);
+ setOutput(null);
+ };
+
+ const handleDropdownChange = (e: React.ChangeEvent) => {
+ const index = Number(e.target.value);
+ const preset = trapPresets[index];
+ presetIndexRef.current = index;
+ setTrapLogic(preset.logic);
+ setSimulatedEvent(preset.event);
+ setOutput(null);
+ };
+
+ return (
+
+
+

+
Drosera Trap Simulator (Unofficial)
+
+
+
+
+
+
+
+ {activeTab === 'simulator' ? (
+ <>
+
+
+
๐ง Trap Logic
+ setTrapLogic(val || '')}
+ theme="vs-dark"
+ />
+
+
+
๐งฑ Simulated Event
+ setSimulatedEvent(val || '')}
+ theme="vs-dark"
+ />
+
+
+
+
+
+ (or)
+
+
+
+
+
+
+
+ {output && (
+
+ Result:
+ {output.message}
+
+ )}
+ >
+ ) : (
+
+ )}
+
+
+
+ );
+}
+
+export default App;
diff --git a/drosera-trap-simulator/src/LiveBoard.tsx b/drosera-trap-simulator/src/LiveBoard.tsx
new file mode 100644
index 0000000..f58e90b
--- /dev/null
+++ b/drosera-trap-simulator/src/LiveBoard.tsx
@@ -0,0 +1,89 @@
+// src/LiveBoard.tsx
+import React, { useEffect, useState } from 'react';
+import { JsonRpcProvider, Contract } from 'ethers';
+
+const LiveBoard: React.FC = () => {
+ const [names, setNames] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [page, setPage] = useState(1);
+ const [search, setSearch] = useState('');
+ const pageSize = 25;
+
+ useEffect(() => {
+ const fetchNames = async () => {
+ try {
+ const provider = new JsonRpcProvider("https://ethereum-holesky-rpc.publicnode.com/");
+ const abi = [
+ "function getDiscordNamesBatch(uint256 start, uint256 end) view returns (string[])"
+ ];
+ const contract = new Contract(
+ "0x4608Afa7f277C8E0BE232232265850d1cDeB600E",
+ abi,
+ provider
+ );
+
+ const result = await contract.getDiscordNamesBatch(0, 2000);
+ const filtered = result.filter((name: string) => name && name !== "DISCORD_USERNAME");
+ setNames(filtered);
+ } catch (err) {
+ console.error("Failed to fetch names", err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchNames();
+ }, []);
+
+ const filtered = names.filter(name => name.toLowerCase().includes(search.toLowerCase()));
+ const paginated = filtered.slice((page - 1) * pageSize, page * pageSize);
+
+ return (
+
+
๐
Proof-of-Trap โ Cadet LiveBoard
+
+
{ setSearch(e.target.value); setPage(1); }}
+ className="mb-4 w-full p-2 rounded bg-gray-700 text-white"
+ />
+
+ {loading ? (
+
Loading real-time data from Drosera testnet...
+ ) : (
+ filtered.length > 0 ? (
+ <>
+
+ {paginated.map((name, idx) => (
+ - {name}
+ ))}
+
+
+
+ Page {page} of {Math.ceil(filtered.length / pageSize)}
+
+
+ >
+ ) : (
+
No active responders found.
+ )
+ )}
+
+ );
+};
+
+export default LiveBoard;
diff --git a/drosera-trap-simulator/src/assets/react.svg b/drosera-trap-simulator/src/assets/react.svg
new file mode 100644
index 0000000..6c87de9
--- /dev/null
+++ b/drosera-trap-simulator/src/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/drosera-trap-simulator/src/index.css b/drosera-trap-simulator/src/index.css
new file mode 100644
index 0000000..dce418d
--- /dev/null
+++ b/drosera-trap-simulator/src/index.css
@@ -0,0 +1,7 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+body {
+ @apply bg-gray-900 text-white;
+}
diff --git a/drosera-trap-simulator/src/main.tsx b/drosera-trap-simulator/src/main.tsx
new file mode 100644
index 0000000..bef5202
--- /dev/null
+++ b/drosera-trap-simulator/src/main.tsx
@@ -0,0 +1,10 @@
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
+import './index.css'
+import App from './App.tsx'
+
+createRoot(document.getElementById('root')!).render(
+
+
+ ,
+)
diff --git a/drosera-trap-simulator/src/vite-env.d.ts b/drosera-trap-simulator/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/drosera-trap-simulator/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/drosera-trap-simulator/tailwind.config.cjs b/drosera-trap-simulator/tailwind.config.cjs
new file mode 100644
index 0000000..579846a
--- /dev/null
+++ b/drosera-trap-simulator/tailwind.config.cjs
@@ -0,0 +1,7 @@
+module.exports = {
+ content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+};
diff --git a/drosera-trap-simulator/tsconfig.app.json b/drosera-trap-simulator/tsconfig.app.json
new file mode 100644
index 0000000..c9ccbd4
--- /dev/null
+++ b/drosera-trap-simulator/tsconfig.app.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["src"]
+}
diff --git a/drosera-trap-simulator/tsconfig.json b/drosera-trap-simulator/tsconfig.json
new file mode 100644
index 0000000..1ffef60
--- /dev/null
+++ b/drosera-trap-simulator/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
diff --git a/drosera-trap-simulator/tsconfig.node.json b/drosera-trap-simulator/tsconfig.node.json
new file mode 100644
index 0000000..9728af2
--- /dev/null
+++ b/drosera-trap-simulator/tsconfig.node.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "target": "ES2022",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/drosera-trap-simulator/vite.config.ts b/drosera-trap-simulator/vite.config.ts
new file mode 100644
index 0000000..8b0f57b
--- /dev/null
+++ b/drosera-trap-simulator/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [react()],
+})