Skip to content
Open
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
72 changes: 64 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,28 +55,84 @@ Violations can be reported by opening a private GitHub issue or contacting a mai

- Node.js >= 18 (we recommend [nvm](https://github.com/nvm-sh/nvm))
- npm >= 9
- Git (for cloning the repository)

### Install Dependencies
### 1. Clone the Repository

If you haven't already, fork the repository on GitHub, then clone your fork locally:

```bash
npm install
git clone https://github.com/YOUR_USERNAME/open-audit.git
cd open-audit
```

### Environment Variables
### 2. Install Dependencies

Install the required Node.js dependencies:

```bash
cp .env.example .env.local
npm install
```

The defaults point to Stellar **testnet**, which is safe for development. No changes are required for running tests.
### 3. Environment Configuration

### Start the Dev Server
Copy the example environment configuration file to `.env`:

```bash
npm run dev
cp .env.example .env
```

The app will be available at [http://localhost:3000](http://localhost:3000).
#### Minimum Required Variables

For basic local development, the default values in `.env` are pre-configured to connect to the Stellar **testnet**. The minimum required variables are:

- `NEXT_PUBLIC_HORIZON_URL`: The Horizon REST API endpoint (defaults to `https://horizon-testnet.stellar.org`).
- `NEXT_PUBLIC_SOROBAN_RPC_URL`: The Soroban RPC endpoint (defaults to `https://soroban-testnet.stellar.org`).
- `NEXT_PUBLIC_NETWORK_PASSPHRASE`: The passphrase matching the target network (defaults to `"Test SDF Network ; September 2015"`).
- `NEXT_PUBLIC_NETWORK`: The network identifier (`testnet`, `mainnet`, or `futurenet`, defaults to `testnet`).

#### Optional Services: PostgreSQL & Redis

For basic development with the in-memory mock data path, **PostgreSQL and Redis are optional**.
- If `DATABASE_URL` is not configured, the app automatically falls back to the in-memory mock data path.
- If `REDIS_URL` is not configured, the app falls back to an in-process memory cache.

#### Setting Up PostgreSQL (Optional)

If you need to test database persistence or work on features requiring the database:
1. Ensure PostgreSQL is running and create a local database:
```bash
createdb open_audit
```
2. Configure the `DATABASE_URL` variable in your `.env` file, for example:
```env
DATABASE_URL="postgresql://user:password@localhost:5432/open_audit"
```
3. Run the database migrations:
```bash
npm run db:migrate
```
4. Seed the database with test data:
```bash
npm run db:seed
```

### 4. Start the Development Server

You can run the application in two modes depending on your needs:

- **Basic Dashboard**: To run the Next.js development server for the frontend dashboard:
```bash
npm run dev
```
The app will be available at [http://localhost:3000](http://localhost:3000).

- **Full WebSocket Server**: To run the monolithic server which includes both the frontend and WebSocket event streaming capabilities:
```bash
npm run dev:ws
```
The app will be available at [http://localhost:3000](http://localhost:3000).


---

Expand Down
52 changes: 47 additions & 5 deletions lib/translator/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,14 +216,56 @@ function buildRegistry(): BlueprintRegistry {
}
}

// 3. Load SDEX (Stellar Classic Order Book) Blueprints
for (const blueprint of createAllSdexBlueprints()) {
register(blueprint);
}

return registry;
}

function interpolate(template: string, values: Record<string, any>): string {
return template.replace(/\{([^}]+)\}/g, (match, key) => {
const [path, format] = key.split(".");
const val = values[path];
if (val && typeof val === "object" && format) {
return val[format] ?? match;
}
return val ?? match;
});
}

function createTranslateFromMapping(mapping: any) {
return (event: RawEvent, lang: Language): TranslationResult | null => {
// 1. Match topics
for (let i = 0; i < mapping.topics.length; i++) {
if (i === 0) {
if (decodeEventName(event.topics[0]) !== mapping.topics[0]) return null;
}
// Future: support matching other topics too
}

const fields: Record<string, any> = {};

// 2. Extract topics[1..]
mapping.event_structure.topics.forEach((t: any, i: number) => {
const hex = event.topics[i + 1];
if (!hex) return;
if (t.type === "address") fields[t.name] = decodeAddress(hex);
else if (t.type === "i128") fields[t.name] = decodeAmount(hex);
else fields[t.name] = hex;
});

// 3. Extract data
if (mapping.event_structure.data) {
const d = mapping.event_structure.data;
if (d.type === "i128") fields[d.name] = decodeAmount(event.data);
else if (d.type === "address") fields[d.name] = decodeAddress(event.data);
else fields[d.name] = event.data;
}

return {
description: interpolate(mapping.english_template, fields),
eventType: mapping.topics[0],
};
};
}

/**
* Builds a `translate` function from a single event-mapping declaration.
* Called by registerUpgrade (eventMappings). Required for the module to load.
Expand Down
Loading