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
231 changes: 178 additions & 53 deletions docs/tutorials/setup-sdk-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,53 @@ tutorials.

## Code

Save the following module in a file named `setupDashClient.mjs`. Later tutorials import from this file.

| Export | Purpose |
| ------ | -------- |
| `setupDashClient()` | Connects and creates key managers from `clientConfig` |
| `createClient()` | Connects to the network |
| `IdentityKeyManager` | Derives identity keys and provides signers for write operations |
| `AddressKeyManager` | Derives platform address keys for address operations |
| `clientConfig` | Shared network and mnemonic configuration |
Save the following two modules side-by-side — `setupDashClient-core.mjs` and
`setupDashClient.mjs` — in the same directory. Later Node tutorials import from
`setupDashClient.mjs`; browser apps can import from `setupDashClient-core.mjs`
directly.

| Export | File | Purpose |
| ------ | ---- | ------- |
| `createClient()` | `setupDashClient-core.mjs` | Connects to the network |
| `IdentityKeyManager` | `setupDashClient-core.mjs` | Derives identity keys and provides signers for write operations |
| `AddressKeyManager` | `setupDashClient-core.mjs` | Derives platform address keys for address operations |
| `dip13KeyPath()` / `KEY_SPECS` | `setupDashClient-core.mjs` | DIP-13 path helper and the 5 standard identity key specs |
| `setupDashClient()` | `setupDashClient.mjs` | Node convenience wrapper — connects and creates key managers from `clientConfig` |
| `clientConfig` | `setupDashClient.mjs` | Network and mnemonic configuration, sourced from `process.env` |

:::{important}
After saving, open `setupDashClient.mjs` and set your mnemonic in the `clientConfig` section near the top
of the file — either edit the value directly or create a `.env` file with `PLATFORM_MNEMONIC`.
After saving, open `setupDashClient.mjs` (the wrapper) and set your mnemonic in
the `clientConfig` section near the top of the file — either edit the value
directly or create a `.env` file with `PLATFORM_MNEMONIC`. The core file has no
configuration to edit.
:::

### Browser-safe core

`setupDashClient-core.mjs` holds everything that works in any JS runtime: the
SDK client factory, DIP-13 path helper, and the two key manager classes.
Browser apps import from this file directly.

```{code-block} javascript
:caption: setupDashClient.mjs
:name: setupDashClient.mjs
:caption: setupDashClient-core.mjs
:name: setupDashClient-core.mjs

/* eslint-disable max-classes-per-file */
//
// Browser-safe core of setupDashClient.
//
// This file contains the parts of setupDashClient that work in any JS runtime:
// - createClient(network)
// - dip13KeyPath(network, identityIndex, keyIndex)
// - IdentityKeyManager
// - AddressKeyManager
// - KEY_SPECS
//
// The Node-only convenience layer (dotenv loading, process.env-driven
// clientConfig, and the setupDashClient() wrapper) lives in setupDashClient.mjs
// alongside this file. Both Node tutorials and browser apps import the same
// IdentityKeyManager from here so there is no copy-paste drift.
//
import {
EvoSDK,
IdentityPublicKeyInCreation,
Expand All @@ -41,16 +68,6 @@ import {
wallet,
} from '@dashevo/evo-sdk';

// Load .env if dotenv is installed (optional — not needed for tutorials).
// Top-level await requires ESM — .mjs extension ensures this.
// eslint-disable-next-line import/no-extraneous-dependencies
try {
const { config } = await import('dotenv');
config();
} catch {
/* dotenv not installed */
}

/** @typedef {import('@dashevo/evo-sdk').Identity} Identity */
/** @typedef {import('@dashevo/evo-sdk').IdentityPublicKey} IdentityPublicKey */
/** @typedef {import('@dashevo/evo-sdk').PlatformAddress} PlatformAddress */
Expand All @@ -75,21 +92,36 @@ try {
// ⚠️ Tutorial helper — holds WIFs in memory for convenience.
// Do not use this pattern as-is for production key management.

// ###########################################################################
// # CONFIGURATION — edit these values for your environment #
// ###########################################################################
// Option 1: Edit the values below directly
// Option 2: Create a .env file with PLATFORM_MNEMONIC and NETWORK
// ---------------------------------------------------------------------------
// Browser-safe hex → bytes (replaces Buffer.from(hex, 'hex'))
// ---------------------------------------------------------------------------

const clientConfig = {
// The network to connect to ('testnet' or 'mainnet')
network: process.env.NETWORK || 'testnet',
/**
* Decode a hex string to a Uint8Array. Browser-safe replacement for
* Buffer.from(hex, 'hex'). Throws on odd-length or non-hex input.
*
* @param {string} hex
* @returns {Uint8Array}
*/
function hexToBytes(hex) {
if (typeof hex !== 'string' || hex.length % 2 !== 0) {
throw new Error('hexToBytes: expected even-length hex string');
}
const out = new Uint8Array(hex.length / 2);
for (let i = 0; i < out.length; i += 1) {
const offset = i * 2;
const chunk = hex.slice(offset, offset + 2);
if (!/^[0-9A-Fa-f]{2}$/.test(chunk)) {
throw new Error(`hexToBytes: invalid hex at offset ${offset}`);
}
out[i] = parseInt(chunk, 16);
}
return out;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// BIP39 mnemonic for wallet operations (identity & address tutorials).
// Leave as null for read-only tutorials.
mnemonic: process.env.PLATFORM_MNEMONIC || null,
// mnemonic: 'your twelve word mnemonic phrase goes here ...',
};
// ---------------------------------------------------------------------------
// DIP-13 key path
// ---------------------------------------------------------------------------

/**
* Build a DIP-13 identity key derivation path.
Expand Down Expand Up @@ -142,7 +174,7 @@ export async function createClient(network = 'testnet') {
// ---------------------------------------------------------------------------

/** Key specs for the 5 standard identity keys (DIP-9). */
const KEY_SPECS = [
export const KEY_SPECS = [
{
keyId: 0,
purpose: Purpose.AUTHENTICATION,
Expand Down Expand Up @@ -379,7 +411,7 @@ class IdentityKeyManager {
`Public key data not available for key ${spec.keyId}. Use createForNewIdentity().`,
);
}
const pubKeyData = Uint8Array.from(Buffer.from(key.publicKey, 'hex'));
const pubKeyData = hexToBytes(key.publicKey);
return new IdentityPublicKeyInCreation({
keyId: spec.keyId,
purpose: spec.purpose,
Expand Down Expand Up @@ -604,6 +636,76 @@ class AddressKeyManager {
}
}

export { IdentityKeyManager, AddressKeyManager };
```

### Node wrapper

`setupDashClient.mjs` is a thin Node-only wrapper that loads `.env`, builds
`clientConfig` from `process.env`, exposes the one-call `setupDashClient()`
helper, and re-exports everything from the core so Node tutorials can import
`IdentityKeyManager`, `AddressKeyManager`, `clientConfig`, and friends from a
single module.

```{code-block} javascript
:caption: setupDashClient.mjs
:name: setupDashClient.mjs

//
// Node-only convenience wrapper around setupDashClient-core.mjs.
//
// This file adds the bits that only make sense in Node tutorials:
// - dotenv loading (PLATFORM_MNEMONIC / NETWORK from .env)
// - clientConfig (network + mnemonic, sourced from process.env)
// - setupDashClient() — the one-call wrapper used by tutorial scripts
//
// Everything browser-safe (createClient, IdentityKeyManager, AddressKeyManager,
// dip13KeyPath, KEY_SPECS) is re-exported from setupDashClient-core.mjs so a
// Node tutorial that imports from this file sees an identical API surface.
//
// Browser apps should import from setupDashClient-core.mjs directly.
//
import { wallet } from '@dashevo/evo-sdk';

import {
createClient,
dip13KeyPath,
KEY_SPECS,
IdentityKeyManager,
AddressKeyManager,
} from './setupDashClient-core.mjs';

// Load .env if dotenv is installed (optional — not needed for tutorials).
// Top-level await requires ESM — .mjs extension ensures this.
// eslint-disable-next-line import/no-extraneous-dependencies
try {
const { config } = await import('dotenv');
config();
} catch {
/* dotenv not installed */
}

/** @typedef {import('@dashevo/evo-sdk').EvoSDK} EvoSDK */

// ⚠️ Tutorial helper — holds WIFs in memory for convenience.
// Do not use this pattern as-is for production key management.

// ###########################################################################
// # CONFIGURATION — edit these values for your environment #
// ###########################################################################
// Option 1: Edit the values below directly
// Option 2: Create a .env file with PLATFORM_MNEMONIC and NETWORK

const clientConfig = {
// The network to connect to ('testnet' or 'mainnet')
network: process.env.NETWORK || 'testnet',

// BIP39 mnemonic for wallet operations (identity & address tutorials).
// Leave as null for read-only tutorials.
mnemonic: process.env.PLATFORM_MNEMONIC || null,
// mnemonic: 'your twelve word mnemonic phrase goes here ...',
};

// ---------------------------------------------------------------------------
// setupDashClient — convenience wrapper
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -657,27 +759,50 @@ export async function setupDashClient({
return { sdk, keyManager, addressKeyManager };
}

export { IdentityKeyManager, AddressKeyManager, clientConfig };
// Re-export everything from the core so existing imports
// (e.g. `import { IdentityKeyManager } from './setupDashClient.mjs'`) keep working.
export {
createClient,
dip13KeyPath,
KEY_SPECS,
IdentityKeyManager,
AddressKeyManager,
clientConfig,
};
```

## What's Happening

The `setupDashClient.mjs` module is a single-file setup that subsequent tutorials import. It handles:
The setup is split across two files so the same code can run under Node and in
the browser without copy-paste drift. Node tutorials import from
`setupDashClient.mjs` (the wrapper); browser apps import from
`setupDashClient-core.mjs` directly.

**`setupDashClient-core.mjs` (browser-safe)** provides the substantive pieces:

- **`createClient()`** — creates a connected SDK instance for a given network
(testnet, mainnet, or local).

- **`IdentityKeyManager`** — derives 5 standard identity keys from your mnemonic
using DIP-9 key paths. Each key serves a specific purpose (authentication,
transfers, encryption). Call methods like `getAuth()` to get
`{ identity, identityKey, signer }` — everything the SDK needs to sign and
submit a transaction.

- **`clientConfig`** — your network and mnemonic, defined once. Set values directly or use a `.env`
file with `NETWORK` and `PLATFORM_MNEMONIC`.
- **`AddressKeyManager`** — derives platform address keys from your mnemonic
using BIP44 paths. These addresses hold credits on the L2 platform layer and
are used for identity creation, top-ups, and credit transfers between
addresses.

- **`setupDashClient()`** — the main entry point for most tutorials. Connects to the network and
creates key managers from `clientConfig`, returning `{ sdk, keyManager, addressKeyManager }`.
- **`dip13KeyPath()`** / **`KEY_SPECS`** — the DIP-13 path helper and the
5-entry spec table used to build identity public keys.

- **`createClient()`** — creates a connected SDK instance for a given network (testnet, mainnet, or
local).
**`setupDashClient.mjs` (Node wrapper)** adds the Node-only conveniences and
re-exports everything from core:

- **`IdentityKeyManager`** — derives 5 standard identity keys from your mnemonic using DIP-9 key
paths. Each key serves a specific purpose (authentication, transfers, encryption). Call methods
like `getAuth()` to get `{ identity, identityKey, signer }` — everything the SDK needs to sign
and submit a transaction.
- **`clientConfig`** — your network and mnemonic, defined once. Set values
directly or use a `.env` file with `NETWORK` and `PLATFORM_MNEMONIC`.

- **`AddressKeyManager`** — derives platform address keys from your mnemonic using BIP44 paths.
These addresses hold credits on the L2 platform layer and are used for identity creation, top-ups,
and credit transfers between addresses.
- **`setupDashClient()`** — the main entry point for most tutorials. Connects
to the network and creates key managers from `clientConfig`, returning
`{ sdk, keyManager, addressKeyManager }`.
5 changes: 5 additions & 0 deletions scripts/tutorial-sync/tutorial-code-map.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ mappings:
block_id:
caption: send-funds.mjs

- source: setupDashClient-core.mjs
doc: setup-sdk-client.md
block_id:
caption: setupDashClient-core.mjs

- source: setupDashClient.mjs
doc: setup-sdk-client.md
block_id:
Expand Down