Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Build outputs
dist
build

# Dependencies
node_modules

# Auto-generated
*.lock
pnpm-lock.yaml
package-lock.json
115 changes: 61 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand All @@ -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.

Expand All @@ -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 |

---

Expand All @@ -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
Expand All @@ -129,25 +135,26 @@ 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 |

---

## 🔧 Configuration

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.

Expand All @@ -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.

Expand Down
34 changes: 31 additions & 3 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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/**"],
},
];
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
11 changes: 9 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ const RateLimitDashboard = lazy(() => import("./pages/RateLimitDashboard"));
const NotFound = lazy(() => import("./pages/NotFound"));

function Fallback() {
return <p style={{ padding: 32, textAlign: "center", color: "var(--muted)" }}>Loading…</p>;
return (
<p style={{ padding: 32, textAlign: "center", color: "var(--muted)" }}>
Loading…
</p>
);
}

export default function App() {
Expand All @@ -33,7 +37,10 @@ export default function App() {
<Routes>
<Route path="/" element={<Home />} />
<Route path="/contract/:id" element={<ContractPage />} />
<Route path="/contract/:id/workspace" element={<DeveloperWorkspace />} />
<Route
path="/contract/:id/workspace"
element={<DeveloperWorkspace />}
/>
<Route path="/wallet/:address" element={<WalletPage />} />
<Route path="/event/:seq" element={<EventPage />} />
<Route path="/search" element={<SearchPage />} />
Expand Down
Loading
Loading