diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..a52b0fb --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +# Build outputs +dist +build + +# Dependencies +node_modules + +# Auto-generated +*.lock +pnpm-lock.yaml +package-lock.json diff --git a/README.md b/README.md index 460a9ee..76befc2 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,10 @@ Decode raw contract calls into plain English, visualise contract relationships, The Octraban Soroban contracts are **deployed and verifiable on the Stellar test network** right now: -| Contract | Contract ID | Stellar Explorer | -|----------|-------------|------------------| +| Contract | Contract ID | Stellar Explorer | +| ----------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | **Explorer / registry** | `CBKPNRQ4D3KTAAE7MMJ4HL6JNF2J2EBG2PSSRW4YHOMHTRHUU734CFWJ` | [View on stellar.expert ↗](https://stellar.expert/explorer/testnet/contract/CBKPNRQ4D3KTAAE7MMJ4HL6JNF2J2EBG2PSSRW4YHOMHTRHUU734CFWJ) | -| **Ticket** | `CDX3V6OE72KUIEEJTBLFCQZFXZCAKOYWYXK2KPRM57M6FLZFAVUSVL42` | [View on stellar.expert ↗](https://stellar.expert/explorer/testnet/contract/CDX3V6OE72KUIEEJTBLFCQZFXZCAKOYWYXK2KPRM57M6FLZFAVUSVL42) | +| **Ticket** | `CDX3V6OE72KUIEEJTBLFCQZFXZCAKOYWYXK2KPRM57M6FLZFAVUSVL42` | [View on stellar.expert ↗](https://stellar.expert/explorer/testnet/contract/CDX3V6OE72KUIEEJTBLFCQZFXZCAKOYWYXK2KPRM57M6FLZFAVUSVL42) | > **Network:** `Test SDF Network ; September 2015` · **RPC:** `https://soroban-testnet.stellar.org` @@ -35,7 +35,7 @@ Point the app at these contracts by keeping the default testnet configuration in Raw Soroban activity is opaque — a swap looks like an unlabelled base64 XDR blob. **Octraban** turns that noise into signal. It pairs an ABI-aware indexer (in the [backend](https://github.com/octraban/octraban_backend) repo) with a rich React UI that renders contract calls, events, and relationships the way a human actually reads them: -> *"Address `GABC…` swapped 100 USDC → 98.7 XLM on StellarSwap at ledger 4,521,983."* +> _"Address `GABC…` swapped 100 USDC → 98.7 XLM on StellarSwap at ledger 4,521,983."_ Beyond read-only exploration, Octraban ships a **developer workspace** — an in-browser editor and sandbox for prototyping contract interactions against live testnet contracts without leaving the tab. @@ -44,54 +44,58 @@ Beyond read-only exploration, Octraban ships a **developer workspace** — an in ## ✨ Features ### 🔍 Explore -| Feature | Description | -|---|---| -| **Contract dashboard** | Metadata, ABI, privileged roles, recent transactions and events for any contract (`/contract/:id`) | -| **Human-readable events** | XDR decoded into plain-English event rows via the ABI registry | -| **Event & sub-invocation views** | Drill into a single event (`/event/:seq`) or the full sub-invocation tree of a call | -| **Wallet history** | All transactions and events for an address (`/wallet/:address`) | -| **Universal search** | Look up contracts, wallets, transactions, and events from one bar (`/search`) | -| **XDR inspector** | Paste any XDR envelope and decode it field-by-field (`/xdr`) | + +| Feature | Description | +| -------------------------------- | -------------------------------------------------------------------------------------------------- | +| **Contract dashboard** | Metadata, ABI, privileged roles, recent transactions and events for any contract (`/contract/:id`) | +| **Human-readable events** | XDR decoded into plain-English event rows via the ABI registry | +| **Event & sub-invocation views** | Drill into a single event (`/event/:seq`) or the full sub-invocation tree of a call | +| **Wallet history** | All transactions and events for an address (`/wallet/:address`) | +| **Universal search** | Look up contracts, wallets, transactions, and events from one bar (`/search`) | +| **XDR inspector** | Paste any XDR envelope and decode it field-by-field (`/xdr`) | ### 🕸️ Visualise -| Feature | Description | -|---|---| -| **Relationship graph** | Interactive contract/address relationship graph (`/graph`) built with Cytoscape | -| **3D dependency graph** | `3d-force-graph` view of contract dependencies and factory deployment trees | -| **Invocation & batch flow charts** | React-Flow diagrams of call flows and batched multi-calls | -| **Address connection graph** | Trace value and call flow between accounts | + +| Feature | Description | +| ---------------------------------- | ------------------------------------------------------------------------------- | +| **Relationship graph** | Interactive contract/address relationship graph (`/graph`) built with Cytoscape | +| **3D dependency graph** | `3d-force-graph` view of contract dependencies and factory deployment trees | +| **Invocation & batch flow charts** | React-Flow diagrams of call flows and batched multi-calls | +| **Address connection graph** | Trace value and call flow between accounts | ### 🛠️ Build -| Feature | Description | -|---|---| -| **Developer workspace** | Monaco-powered editor + file explorer scoped to a contract (`/contract/:id/workspace`) | -| **Sandbox** | Run and share snippets against live contracts using a WebContainer runtime (`/sandbox`, `/sandbox/:id`) | -| **Batch multi-call** | Compose and preview batched contract invocations (`/batch`) | -| **ABI upload** | Drop a local ABI to decode events for unregistered contracts | -| **Guided setup** | First-run configuration walkthrough (`/setup`) | + +| Feature | Description | +| ----------------------- | ------------------------------------------------------------------------------------------------------- | +| **Developer workspace** | Monaco-powered editor + file explorer scoped to a contract (`/contract/:id/workspace`) | +| **Sandbox** | Run and share snippets against live contracts using a WebContainer runtime (`/sandbox`, `/sandbox/:id`) | +| **Batch multi-call** | Compose and preview batched contract invocations (`/batch`) | +| **ABI upload** | Drop a local ABI to decode events for unregistered contracts | +| **Guided setup** | First-run configuration walkthrough (`/setup`) | ### 📊 Operate -| Feature | Description | -|---|---| -| **RPC metrics dashboard** | Latency, throughput, and circuit-breaker status for the RPC layer (`/rpc-metrics`) | -| **Rate-limit dashboard** | Admin view of rate-limit hits (`/admin/rate-limits`) | -| **Network switcher & comparison** | Toggle networks and compare state side-by-side | -| **Wallet integration** | Connect with **Freighter** for signing and account context | + +| Feature | Description | +| --------------------------------- | ---------------------------------------------------------------------------------- | +| **RPC metrics dashboard** | Latency, throughput, and circuit-breaker status for the RPC layer (`/rpc-metrics`) | +| **Rate-limit dashboard** | Admin view of rate-limit hits (`/admin/rate-limits`) | +| **Network switcher & comparison** | Toggle networks and compare state side-by-side | +| **Wallet integration** | Connect with **Freighter** for signing and account context | --- ## 🧱 Tech Stack -| Layer | Technology | -|---|---| -| **Framework** | React 18 + TypeScript, bundled with **Vite** | -| **Routing** | React Router | -| **Data** | TanStack Query (server state, caching, retries) | -| **Stellar** | `@stellar/stellar-sdk`, `@stellar/freighter-api` | -| **Visualisation** | Cytoscape, `3d-force-graph`, React-Flow | -| **In-browser IDE** | Monaco Editor + `@webcontainer/api` sandbox | -| **Testing** | Vitest + Testing Library (jsdom) | -| **Tooling** | ESLint, Prettier, TypeScript strict mode | +| Layer | Technology | +| ------------------ | ------------------------------------------------ | +| **Framework** | React 18 + TypeScript, bundled with **Vite** | +| **Routing** | React Router | +| **Data** | TanStack Query (server state, caching, retries) | +| **Stellar** | `@stellar/stellar-sdk`, `@stellar/freighter-api` | +| **Visualisation** | Cytoscape, `3d-force-graph`, React-Flow | +| **In-browser IDE** | Monaco Editor + `@webcontainer/api` sandbox | +| **Testing** | Vitest + Testing Library (jsdom) | +| **Tooling** | ESLint, Prettier, TypeScript strict mode | --- @@ -114,11 +118,13 @@ src/ ## 🚀 Getting Started ### Prerequisites + - **Node.js ≥ 18** - The [Octraban backend](https://github.com/octraban/octraban_backend) running locally (provides the indexer API the UI reads from), or a reachable indexer URL - A [Freighter](https://www.freighter.app/) wallet for signing (optional, for write flows) ### Installation + ```bash git clone https://github.com/octraban/octraban_frontend.git cd octraban_frontend @@ -129,13 +135,14 @@ npm run dev # http://localhost:5173 ``` ### Scripts -| Command | Description | -|---|---| -| `npm run dev` | Start the Vite dev server | -| `npm run build` | Type-check and build for production | -| `npm run preview` | Preview the production build locally | -| `npm test` | Run the Vitest suite | -| `npm run test:watch` | Run tests in watch mode | + +| Command | Description | +| -------------------- | ------------------------------------ | +| `npm run dev` | Start the Vite dev server | +| `npm run build` | Type-check and build for production | +| `npm run preview` | Preview the production build locally | +| `npm test` | Run the Vitest suite | +| `npm run test:watch` | Run tests in watch mode | --- @@ -143,11 +150,11 @@ npm run dev # http://localhost:5173 Copy `.env.example` → `.env` and adjust: -| Variable | Default | Description | -|---|---|---| -| `VITE_INDEXER_URL` | `http://localhost:3001` | Octraban indexer API the UI reads from | -| `VITE_SOROBAN_RPC_URL` | `https://soroban-testnet.stellar.org` | Soroban RPC endpoint (used by the Sandbox) | -| `VITE_NETWORK_PASSPHRASE` | `Test SDF Network ; September 2015` | Stellar network passphrase | +| Variable | Default | Description | +| ------------------------- | ------------------------------------- | ------------------------------------------ | +| `VITE_INDEXER_URL` | `http://localhost:3001` | Octraban indexer API the UI reads from | +| `VITE_SOROBAN_RPC_URL` | `https://soroban-testnet.stellar.org` | Soroban RPC endpoint (used by the Sandbox) | +| `VITE_NETWORK_PASSPHRASE` | `Test SDF Network ; September 2015` | Stellar network passphrase | The defaults point at **Stellar testnet**, so a fresh checkout talks to the live testnet deployment out of the box. @@ -157,7 +164,7 @@ The defaults point at **Stellar testnet**, so a fresh checkout talks to the live Octraban is split across three repositories: -- **octraban_frontend** *(this repo)* — the explorer & developer workspace UI. +- **octraban_frontend** _(this repo)_ — the explorer & developer workspace UI. - **[octraban_backend](https://github.com/octraban/octraban_backend)** — the API + indexer that ingests on-chain data and serves it to the UI (`:3001`). - **[octraban_contract](https://github.com/octraban/octraban_contract)** — the Soroban smart contracts (explorer registry + ticket), deployed to testnet. diff --git a/eslint.config.js b/eslint.config.js index 7593ac5..340d125 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -6,17 +6,45 @@ export default [ ...tseslint.configs.recommended, { rules: { - "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + "@typescript-eslint/no-unused-vars": [ + "error", + { argsIgnorePattern: "^_" }, + ], "@typescript-eslint/no-explicit-any": "warn", }, }, { - files: [ "src/components/AddressConnectionGraph.tsx", "src/components/ContractDependencyGraph3D.tsx", "src/components/DependencyVisualizer.tsx", "src/components/FileExplorer.tsx", "src/components/RawDataViewer.tsx", "src/components/ReadContract.tsx", "src/components/SimulateButton.tsx", "src/components/WriteContract.tsx", "src/pages/ContractPage.tsx", "src/pages/RpcMetricsDashboard.tsx", "src/pages/SandboxPage.tsx", "src/pages/SetupPage.tsx", "src/pages/XdrInspector.tsx", "src/services/dependencies.ts", "src/services/sandbox-api.ts", "src/services/webcontainer.ts", "src/env.d.ts", "test/api.test.ts", "test/hooks.test.tsx", "test/ErrorBoundary.test.tsx"], + files: [ + "src/components/AddressConnectionGraph.tsx", + "src/components/ContractDependencyGraph3D.tsx", + "src/components/DependencyVisualizer.tsx", + "src/components/FileExplorer.tsx", + "src/components/RawDataViewer.tsx", + "src/components/ReadContract.tsx", + "src/components/SimulateButton.tsx", + "src/components/SubInvocationGraph.tsx", + "src/components/WriteContract.tsx", + "src/pages/BatchMultiCall.tsx", + "src/pages/ContractPage.tsx", + "src/pages/RateLimitDashboard.tsx", + "src/pages/RpcMetricsDashboard.tsx", + "src/pages/SandboxPage.tsx", + "src/pages/SetupPage.tsx", + "src/pages/XdrInspector.tsx", + "src/services/dependencies.ts", + "src/services/sandbox-api.ts", + "src/services/webcontainer.ts", + "src/env.d.ts", + "test/api.test.ts", + "test/hooks.test.tsx", + "test/ErrorBoundary.test.tsx", + "test/SearchPage.test.tsx", + ], rules: { "@typescript-eslint/no-explicit-any": "off", }, }, { - ignores: ["node_modules/**", "dist/**"], + ignores: ["node_modules/**", "dist/**", "build/**"], }, ]; diff --git a/index.html b/index.html index 8840c98..0c4ccb0 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,4 @@ - +
diff --git a/package.json b/package.json index 34322bc..abc522f 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,9 @@ "build": "tsc && vite build", "preview": "vite preview", "lint": "eslint .", + "lint:fix": "eslint . --fix", + "format": "prettier --check .", + "format:fix": "prettier --write .", "test": "vitest run", "test:watch": "vitest" }, diff --git a/src/App.tsx b/src/App.tsx index 256243f..ef05549 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -21,7 +21,11 @@ const RateLimitDashboard = lazy(() => import("./pages/RateLimitDashboard")); const NotFound = lazy(() => import("./pages/NotFound")); function Fallback() { - returnLoading…
; + return ( ++ Loading… +
+ ); } export default function App() { @@ -33,7 +37,10 @@ export default function App() {
- Drop a contract ABI .json file here
+ Drop a contract ABI{" "}
+ .json file here
- or click to browse — stored in session memory only, never sent to the server + or click to browse — stored in session memory only, never sent to the + server
diff --git a/src/components/ActionBar.tsx b/src/components/ActionBar.tsx index 5621bdb..9e408a3 100644 --- a/src/components/ActionBar.tsx +++ b/src/components/ActionBar.tsx @@ -28,11 +28,19 @@ const ActionBar: React.FC