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
118 changes: 118 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Tutorial code for [Dash Platform](https://docs.dash.org/platform) demonstrating how to interact with the Dash network using `@dashevo/evo-sdk`. Covers identities, DPNS names, data contracts, and documents.

## Commands

```bash
npm test # Read-only tests (~2min, safe to run anytime)
npm run test:read-write # Write tests (destructive, consumes testnet credits, ~5min)
npm run test:all # Both suites sequentially
npm run test:setup # Mocha tests for setupDashClient configuration

npm run lint # TypeScript type-check all JS files (tsc)
npm run fmt # Format with Prettier
```

**Running a single tutorial directly:**

```bash
node connect.mjs
node 1-Identities-and-Names/identity-retrieve.mjs
```

**Running a single test file:**

```bash
node --test --test-timeout=120000 test/read-only.test.mjs
```

## Architecture

### Tutorial Structure

Each tutorial is a standalone `.mjs` ESM file with top-level `await`. The pattern is consistent:

```javascript
import { setupDashClient } from '../setupDashClient.mjs';

const { sdk, keyManager } = await setupDashClient();

try {
// Tutorial logic — use sdk and keyManager
console.log(result.toJSON());
} catch (e) {
console.error('Something went wrong:\n', e.message);
}
```

### `setupDashClient.mjs`

The central helper (~500 lines) that all tutorials import. It handles:

- Loading `.env` via `dotenv`
- BIP39 wallet derivation from `PLATFORM_MNEMONIC`
- DIP-13 key path derivation
- SDK instantiation (`createClient(network)`)
- Key manager setup — returns `{ sdk, keyManager, addressKeyManager }`

`keyManager.identityId` resolves automatically from the mnemonic. `keyManager.getAuth()` returns the identity, key, and signer needed for signing transactions.

> **Note:** The in-memory key pattern in `setupDashClient` is for tutorials only — not suitable for production.

### Test Framework

Tests use Node.js built-in test runner. Each test runs a tutorial as a **subprocess** via `test/run-tutorial.mjs` and validates:

- Exit code is 0
- `stdout`/`stderr` match expected regex patterns
- Process was not killed (no timeout)

`test/assertions.mjs` provides helpers like `extractId()` and `extractKeyId()` to capture values from output for use in subsequent dependent tests.

**Read-write tests** maintain a shared state object to pass IDs (contract IDs, document IDs, etc.) between sequential dependent tests.

### Derivation Paths

All key derivation uses standard Dash paths. External wallets/tools must use the same paths for compatibility.

| Key type | Testnet path | Mainnet path |
| - | - | - |
| Platform address (BIP44) | `m/44'/1'/0'/0/i` | `m/44'/5'/0'/0/i` |
| Identity master key (DIP-13) | `m/9'/1'/5'/0'/0'/0'/0'` | `m/9'/5'/5'/0'/0'/0'/0'` |
| Identity keys 0–4 (DIP-13) | `m/9'/1'/5'/0'/0'/0'/k'` | `m/9'/5'/5'/0'/0'/0'/k'` |

Where `i` = address index and `k` = key index (0=MASTER, 1=HIGH auth, 2=CRITICAL auth, 3=TRANSFER, 4=ENCRYPTION).

No BIP39 passphrase is used.

### Environment Variables

Copy `.env.example` to `.env`. Key variables:

| Variable | Purpose |
| - | - |
| `PLATFORM_MNEMONIC` | BIP39 mnemonic; required for all write operations |
| `NETWORK` | `testnet` (default) or `mainnet` |
| `DATA_CONTRACT_ID` | Output of `contract-register-minimal.mjs` |
| `DOCUMENT_ID` | Output of `document-submit.mjs` |
| `RECIPIENT_ID` | Identity ID for credit transfers |
| `RECIPIENT_PLATFORM_ADDRESS` | `tdash1...` address for send-funds |

Read-only tests skip gracefully when `PLATFORM_MNEMONIC` is unset.

### Directory Layout

- **Root** — shared utilities (`setupDashClient.mjs`, `connect.mjs`, `create-wallet.mjs`, `view-wallet.mjs`, `send-funds.mjs`)
- **`1-Identities-and-Names/`** — identity registration, top-up, key management, DPNS name registration/lookup
- **`2-Contracts-and-Documents/`** — data contract variants (minimal, indexed, binary, timestamps, history, NFT), document CRUD, NFT operations
- **`test/`** — test runner, assertions, read-only and read-write test suites
- **`docs/`** — HTML/JS interactive tutorial runner (separate from Node tutorials)

### Linting / Types

TypeScript (`tsconfig.json`) checks JS files with `strict: true`, `noUnusedLocals: true`, targeting Node16 modules. ESLint uses `airbnb-base`. Prettier uses single quotes, 2-space tabs, trailing commas.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ npm ci
1. Fund the platform address using the bridge URL printed in the previous step
1. Create a `.env` file (see [`.env.example`](./.env.example)) and set `PLATFORM_MNEMONIC` to the
mnemonic from step 2. Set `NETWORK` if needed (defaults to `testnet`).
1. To inspect an existing wallet after configuring `PLATFORM_MNEMONIC`, run `node view-wallet.mjs`

Proceed with the [Identities and Names tutorials](./1-Identities-and-Names/) first and the
[Contracts and Documents tutorials](./2-Contracts-and-Documents/) next. They align with the
Expand Down Expand Up @@ -80,6 +81,21 @@ npm run test:read-write
npm run test:all
```

### Importing an existing wallet

If you already have a Dash identity created with another tool (e.g. [Dash
Bridge](https://bridge.thepasta.org/)), you can use it directly by setting `PLATFORM_MNEMONIC` to
your existing mnemonic. Run `node view-wallet.mjs` to confirm the derived address and identity ID.

For compatibility, the external tool must use the same derivation paths (no BIP39 passphrase):

| Key type | Testnet | Mainnet |
| - | - | - |
| Platform address (BIP44) | `m/44'/1'/0'/0/i` | `m/44'/5'/0'/0/i` |
| Identity keys (DIP-13) | `m/9'/1'/5'/0'/0'/0'/k'` | `m/9'/5'/5'/0'/0'/0'/k'` |

The first platform address (`i=0`) must be funded for top-up and send-funds operations.

## Contributing

PRs accepted.
Expand Down
36 changes: 36 additions & 0 deletions view-wallet.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
createClient,
clientConfig,
AddressKeyManager,
IdentityKeyManager,
} from './setupDashClient.mjs';

const { mnemonic, network } = clientConfig;

if (!mnemonic) {
console.error('No mnemonic found. Set PLATFORM_MNEMONIC in your .env file.');
process.exit(1);
}

try {
const sdk = await createClient(network);
const addressKeyManager = await AddressKeyManager.create({ sdk, mnemonic, network });
const { bech32m, path } = addressKeyManager.primaryAddress;

let identityId = 'No identity found for this mnemonic';
try {
const keyManager = await IdentityKeyManager.create({ sdk, mnemonic, network });
identityId = keyManager.identityId;
} catch (e) {
if (!e.message?.includes('No identity found for the given mnemonic')) throw e;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// ⚠️ Never log mnemonics in real applications
console.log('Network: ', network);
console.log('Mnemonic: ', mnemonic);
Comment thread
thephez marked this conversation as resolved.
console.log(`First address: ${bech32m} (${path})`);
console.log('Fund address: ', `https://bridge.thepasta.org/?address=${bech32m}`);
console.log('Identity ID: ', identityId);
} catch (e) {
console.error('Something went wrong:\n', e.message);
}