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
16 changes: 11 additions & 5 deletions _static/dashmint-lite.html
Original file line number Diff line number Diff line change
Expand Up @@ -119,18 +119,24 @@ <h2>Browse cards</h2>
// package and serves it as a browser-native ES module. Pinned to the same
// version the React app at ../package.json depends on so both UIs behave
// identically against the same testnet contract.
import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@3.1.0-dev.1';
import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@4.0.0-rc.2';

// The "card" data contract is already published on testnet by the React app.
// Anyone querying with the same contract id hits the same documents.
const CONTRACT_ID = '4eJR4pgV9mQdyoodfTTwFUp3SYBRJbUrJ5X1ViN2zBhY';
// The token-enabled "card" data contract is already published on testnet by
// the React app. Anyone querying with the same contract id hits the same
// documents.
const CONTRACT_ID = '5hK6SMfN4m2vU1t9qhvngUUQjsXeMNwr8MZdFeGBH8Aa';
const DOC_TYPE = 'card';

// Connect to testnet. testnetTrusted() uses the SDK's bundled list of trusted
// nodes — no node URL or config needed. connect() does the gRPC handshake
// + initial sync. No identity or signing is required for read-only queries.
//
// Workaround: pin the platform protocol version for evo-sdk dev.6 so the
// SDK doesn't ask testnet for a newer protocol it can't decode. Mirrors
// PLATFORM_VERSION_OVERRIDE in setupDashClient-core.mjs. Remove once a
// fixed SDK release lands.
async function connectSdk() {
const sdk = EvoSDK.testnetTrusted();
const sdk = EvoSDK.testnetTrusted({ version: 11 });
await sdk.connect();
return sdk;
}
Expand Down
2 changes: 1 addition & 1 deletion _static/dashnote-lite.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ <h2>Get note by ID</h2>
// package and serves it as a browser-native ES module. Pinned to the same
// version the React app at ../package.json depends on so both UIs behave
// identically against the same testnet contract.
import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@3.1.0-dev.1';
import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@4.0.0-rc.2';

// The "note" data contract is already published on testnet by the React app.
// Anyone querying with the same contract id hits the same documents.
Expand Down
2 changes: 1 addition & 1 deletion _static/dashproof-lite.html
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ <h2>History by chainId</h2>
// package and serves it as a browser-native ES module. Pinned to the same
// version the React app at ../package.json depends on so both UIs behave
// identically against the same testnet contract.
import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@3.1.0-dev.1';
import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@4.0.0-rc.2';

// The "anchor" data contract is already published on testnet by the React app.
// Anyone querying with the same contract id hits the same documents.
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/connecting-to-testnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Platform services are provided via a combination of HTTP and gRPC connections to

## Prerequisites

- An installation of [NodeJS v20 or higher](https://nodejs.org/en/download/)
- An installation of [NodeJS v22 or higher](https://nodejs.org/en/download/)

## Connect via Dash SDK

Expand Down
302 changes: 284 additions & 18 deletions docs/tutorials/example-apps/dashmint-lab.md

Large diffs are not rendered by default.

34 changes: 28 additions & 6 deletions docs/tutorials/example-apps/dashnote.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ If you just want the mental model: read the architecture table, then `createNote
- A configured client: [Setup SDK Client](../setup-sdk-client.md) — Dashnote re-uses `setupDashClient-core.mjs`
- A registered identity: [Register an Identity](../identities-and-names/register-an-identity.md)
- Familiarity with data contracts: [Register a Data Contract](../contracts-and-documents/register-a-data-contract.md)
- Node >= 20 and a funded testnet identity (BIP-39 mnemonic + identity index) for write operations
- Node >= 22 and a funded testnet identity (BIP-39 mnemonic + identity index) for write operations
- Read-only browse works without any credentials against the bundled default contract

## Clone and run
Expand Down Expand Up @@ -255,6 +255,7 @@ Each operation file is intentionally small. The app-level pattern is: validate i
* SDK method: sdk.documents.create({ document, identityKey, signer })
*/
import type { Logger } from "../lib/logger";
import { PLATFORM_VERSION_OVERRIDE } from "../../../../platformVersion.mjs";
import { loadSdkModule } from "./sdkModule";
import type { DashKeyManager, DashSdk } from "./types";

Expand Down Expand Up @@ -297,7 +298,7 @@ export async function createNote({

const json =
typeof document.toJSON === "function"
? (document.toJSON() as Record<string, unknown>)
? (document.toJSON(PLATFORM_VERSION_OVERRIDE) as Record<string, unknown>)
: {};
const noteId = String(json.$id ?? json.id ?? "");
if (!noteId) {
Expand All @@ -310,7 +311,13 @@ export async function createNote({

### Update a note

`updateNote.ts` is the canonical fetch-then-bump-revision write. It calls `sdk.documents.get` to read the on-chain revision, increments it by one, builds a new `Document` with the same id and ownerId, and submits via `sdk.documents.replace`. Replays without bumping the revision are rejected by the state transition.
`updateNote.ts` is the canonical fetch-then-bump-revision write:

- Call `sdk.documents.get` to read the current on-chain revision.
- Increment it by one and build a new `Document` with the same id and ownerId.
- Submit via `sdk.documents.replace`. Replays without bumping the revision are rejected by the state transition.

The optional `expectedRevision` parameter guards against a concurrent edit: if the on-chain revision no longer matches what the caller last loaded, the update is refused with a "reload and try again" error instead of silently overwriting the newer version.

```{code-block} typescript
:caption: updateNote.ts
Expand All @@ -320,6 +327,10 @@ export async function createNote({
* Update an existing note. Fetches the current document to bump its revision,
* then submits a replace state transition.
*
* Pass `expectedRevision` to refuse the update if the network's revision
* doesn't match — i.e. the note was changed on the network after the local
* copy was loaded.
*
* SDK methods:
* sdk.documents.get(contractId, documentTypeName, documentId)
* sdk.documents.replace({ document, identityKey, signer })
Expand All @@ -335,6 +346,7 @@ export interface UpdateNoteParams {
noteId: string;
title?: string;
message: string;
expectedRevision?: number;
log?: Logger;
}

Expand All @@ -345,6 +357,7 @@ export async function updateNote({
noteId,
title,
message,
expectedRevision,
log,
}: UpdateNoteParams): Promise<bigint> {
log?.(`Saving note ${noteId}…`);
Expand All @@ -354,8 +367,18 @@ export async function updateNote({
throw new Error(`Note ${noteId} not found.`);
}

const currentRevision = BigInt(existingDoc.revision ?? 0);
if (
expectedRevision !== undefined &&
currentRevision !== BigInt(expectedRevision)
) {
throw new Error(
`Note changed on network (you had revision ${expectedRevision}, network is at ${currentRevision}). Reload your notes and try again.`,
);
}

const { Document } = await loadSdkModule();
const revision = BigInt(existingDoc.revision ?? 0) + 1n;
const revision = currentRevision + 1n;
const trimmedTitle = title?.trim();
const document = new Document({
properties: {
Expand Down Expand Up @@ -431,7 +454,7 @@ export async function deleteNote({
The note contract is intentionally minimal: one document type, two user-editable fields, two indices to support the recent-notes list. Key choices worth calling out:

- `documentsMutable: true` and `canBeDeleted: true` — notes are editable and deletable.
- `maxLength: 120` for `title` and `maxLength: 10000` for `message` are **UTF-8 byte budgets**, not character counts. The editor's progress bar reflects bytes; emoji and non-ASCII sequences consume more of the budget than ASCII.
- `maxLength: 120` for `title` caps the title; `message` carries no `maxLength` and is instead bounded by Platform's per-field byte limit. The editor's progress bar tracks the `message` byte count against that limit — emoji and non-ASCII sequences consume more of the budget than ASCII.
- `byOwnerUpdated` (`$ownerId`, `$updatedAt`) is the index the recent-notes list paginates on; `byOwnerCreated` is its created-time sibling.

`registerContract` builds the `DataContract`, calls `setConfig()` to lock in those choices, then publishes via `sdk.contracts.publish`. `ensureContract` is the lazy wrapper used by the login flow: re-use a saved contract ID if one is present, otherwise register a fresh one.
Expand Down Expand Up @@ -464,7 +487,6 @@ export const NOTE_SCHEMAS = {
},
message: {
type: "string",
maxLength: 10000,
position: 1,
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ console.log('Identity balance before withdrawal:', identity.balance);
// Default: testnet faucet address. Replace or override via WITHDRAWAL_ADDRESS.
const toAddress =
process.env.WITHDRAWAL_ADDRESS || 'yXWJGWuD4VBRMp9n2MtXQbGpgSeWyTRHme';
const amount = 190000n; // Credits to withdraw
const amount = 1000000n; // Credits to withdraw (protocol minimum)
const amountDash = Number(amount) / (1000 * 100000000);

console.log(`Withdrawing ${amount} credits (${amountDash} DASH)`);
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Building on Dash Platform requires first registering an Identity and then regist

The tutorials in this section are written in JavaScript and use [Node.js](https://nodejs.org/en/about/). The following prerequisites are necessary to complete the tutorials:

- [Node.js](https://nodejs.org/en/) (v20+)
- [Node.js](https://nodejs.org/en/) (v22+)
- Familiarity with JavaScript asynchronous functions using [async/await](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await)
- The [Dash JavaScript SDK](https://www.npmjs.com/package/@dashevo/evo-sdk) (see [Connecting to a Network](../tutorials/connecting-to-testnet.md#1-install-the-dash-sdk))

Expand Down
11 changes: 8 additions & 3 deletions docs/tutorials/setup-sdk-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import {
SecurityLevel,
wallet,
} from '@dashevo/evo-sdk';
import { PLATFORM_VERSION_OVERRIDE } from './platformVersion.mjs';

/** @typedef {import('@dashevo/evo-sdk').Identity} Identity */
/** @typedef {import('@dashevo/evo-sdk').IdentityPublicKey} IdentityPublicKey */
Expand Down Expand Up @@ -144,6 +145,8 @@ export async function dip13KeyPath(network, identityIndex, keyIndex) {
// SDK client helpers
// ---------------------------------------------------------------------------

export { PLATFORM_VERSION_OVERRIDE };

/**
* Create and connect an EvoSDK client for the selected network.
*
Expand All @@ -152,9 +155,11 @@ export async function dip13KeyPath(network, identityIndex, keyIndex) {
*/
export async function createClient(network = 'testnet') {
const factories = /** @type {Record<string, () => EvoSDK>} */ ({
testnet: () => EvoSDK.testnetTrusted(),
mainnet: () => EvoSDK.mainnetTrusted(),
local: () => EvoSDK.localTrusted(),
testnet: () =>
EvoSDK.testnetTrusted({ version: PLATFORM_VERSION_OVERRIDE }),
mainnet: () =>
EvoSDK.mainnetTrusted({ version: PLATFORM_VERSION_OVERRIDE }),
local: () => EvoSDK.localTrusted({ version: PLATFORM_VERSION_OVERRIDE }),
});

const factory = factories[network];
Expand Down
12 changes: 12 additions & 0 deletions scripts/tutorial-sync/tutorial-code-map.yml
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ mappings:
caption: contract.ts
language: typescript

- source: example-apps/dashmint-lab/src/dash/dashMintToken.ts
doc: example-apps/dashmint-lab.md
block_id:
caption: dashMintToken.ts
language: typescript

- source: example-apps/dashmint-lab/src/dash/withAuthedCard.ts
doc: example-apps/dashmint-lab.md
block_id:
Expand All @@ -217,6 +223,12 @@ mappings:
caption: transferCard.ts
language: typescript

- source: example-apps/dashmint-lab/src/dash/transferDashMintTokens.ts
doc: example-apps/dashmint-lab.md
block_id:
caption: transferDashMintTokens.ts
language: typescript

- source: example-apps/dashmint-lab/src/dash/setPrice.ts
doc: example-apps/dashmint-lab.md
block_id:
Expand Down
Loading