Skip to content

docs(tokens): top-level Tokens category with shielded/unshielded token tutorials#1101

Open
Olanetsoft wants to merge 39 commits into
mainfrom
docs/create-transfer-shielded-unshielded-tokens
Open

docs(tokens): top-level Tokens category with shielded/unshielded token tutorials#1101
Olanetsoft wants to merge 39 commits into
mainfrom
docs/create-transfer-shielded-unshielded-tokens

Conversation

@Olanetsoft

@Olanetsoft Olanetsoft commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Turns Tokens into a top-level, expandable sidebar category and adds two tutorials for creating and transferring custom tokens in Compact.

Changes

  • Category restructuredocs/tokens/_category_.yaml now uses link: type: generated-index (same pattern as Guides), so Tokens renders as a real expandable category with Overview as its explicit first entry.
  • Overview — the existing tokens content moved from index.mdxoverview.mdx (sidebar_position: 1), body unchanged aside from a pointer to the two new tutorials.
  • Create and transfer an unshielded token (unshielded-token.mdx, position 2) — transparent token: on-chain balances, mintUnshieldedToken / sendUnshielded, full deploy-and-test harness.
  • Create and transfer a shielded token (shielded-token.mdx, position 3) — privacy-preserving token: value in immutable coins, witnesses, mintShieldedToken / sendImmediateShielded, confirmed via the wallet's shielded balance.

Convert the Tokens section into a generated-index category with Overview
as the first page (moved from index.mdx), and add two tutorials:

- Create and transfer an unshielded token
- Create and transfer a shielded token

Doc URLs in the source are rewritten as relative paths and the two
tutorials cross-link each other.
@Olanetsoft Olanetsoft requested review from a team as code owners June 25, 2026 16:18
@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
midnight-wiki Ready Ready Preview, Comment Jul 6, 2026 1:45pm

Request Review

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

Summary

Status Count
🔍 Total 10
✅ Successful 10
⏳ Timeouts 0
🔀 Redirected 0
👻 Excluded 0
❓ Unknown 0
🚫 Errors 0
⛔ Unsupported 0
Full Github Actions output

Comment thread docs/tokens/shielded-token.mdx
Comment thread docs/tokens/shielded-token.mdx
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/unshielded-token.mdx Outdated
Comment thread docs/tokens/unshielded-token.mdx Outdated
Comment thread docs/tokens/unshielded-token.mdx Outdated
Comment thread docs/tokens/unshielded-token.mdx Outdated
Comment thread docs/tokens/unshielded-token.mdx Outdated
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

🚀 Preview Deployment

Deployment Ready

🔗 Preview URL: https://pr-1101-midnight-docs.vercel.app

📝 Latest commit: f42bb04
Updated: Jul 6, 2026, 1:47 PM UTC


This preview updates automatically when you push new commits to this PR.

Rewrite passive-voice sentences flagged by Midnight.Readability into
active voice, and replace a 'the user' phrasing flagged by
Midnight.SecondPerson. The SPDX license header is unchanged.
Comment thread docs/tokens/shielded-token.mdx

@oduameh oduameh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Review withdrawn)

@oduameh oduameh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work on this PR. These are substantial, well-structured tutorials that walk developers through both unshielded and shielded tokens end to end. The progression from transparent balances to immutable coins is well motivated and the code examples are thorough.

Left inline suggestions that can be batch committed.

Top recurring issues:

  • Em-dashes appear throughout both tutorials. The Midnight docs style guide uses commas, periods, colons, or restructured sentences instead. Each instance below has an inline fix.
  • Compiler version: both tutorials reference compactc 0.31.0. Worth verifying against the current compatibility matrix before merging.
  • Intro scope: the unshielded tutorial intro says it covers both tokens, but only this file covers the unshielded one.

Additional notes (not inlined):

  • The shielded tutorial's deploy script duplicates the wallet-funding flow from the unshielded tutorial nearly verbatim (~160 lines). Consider extracting the shared setup into a partial or collapsible block to reduce maintenance surface.
  • "Midnight has no native token live on the network yet" (unshielded-token.mdx, line 21): with Mainnet launched, this may need qualifying (e.g. 'native mNIGHT is not yet live').
  • The genesis wallet seed 0x00...001 is shown in the run command. Consider adding a note that this seed is for local use only.

27 suggestions, 1 comment across 2 files.

Comment thread docs/tokens/unshielded-token.mdx Outdated
Comment thread docs/tokens/unshielded-token.mdx Outdated
Comment thread docs/tokens/unshielded-token.mdx Outdated
Comment thread docs/tokens/unshielded-token.mdx Outdated
Comment thread docs/tokens/unshielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/unshielded-token.mdx Outdated

@oduameh oduameh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Source-verified technical review. Every Compact standard library claim was checked against the actual source at LFDT-Minokawa/compact/compiler/standard-library.compact.

All function signatures confirmed (mintUnshieldedToken, sendUnshielded, unshieldedBalanceGte, mintShieldedToken, sendShielded, sendImmediateShielded, evolveNonce, shieldedBurnAddress, pad, persistentHash, all Either type wrapping). One field name discrepancy and two protocol-level claims that cannot be verified from the standard library source are flagged below.

Structural notes:

  • The shielded tutorial's deploy script duplicates ~160 lines of wallet-funding flow from the unshielded tutorial. The PR notes this is intentional ("included here in full so it runs on its own"), but it creates a maintenance burden. Consider a collapsible block or partial.
  • Renaming index.mdx to overview.mdx and switching to generated-index changes the URL from /tokens to /tokens/overview. Any existing links to /tokens now land on the auto-generated index page. Flagged inline on _category_.yaml.

4 suggestions, 7 comments across 3 files.

Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/shielded-token.mdx Outdated
Comment thread docs/tokens/_category_.yaml
Comment thread docs/tokens/_category_.yaml
Comment thread docs/tokens/unshielded-token.mdx Outdated
Olanetsoft and others added 8 commits June 29, 2026 12:27
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Comment thread docs/tokens/shielded-token.mdx
Comment thread docs/tokens/shielded-token.mdx
Comment thread docs/tokens/shielded-token.mdx
Olanetsoft and others added 4 commits June 29, 2026 12:45
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Comment thread docs/tokens/shielded-token.mdx
Comment thread docs/tokens/shielded-token.mdx Outdated
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Comment thread docs/tokens/shielded-token.mdx
Comment thread docs/tokens/shielded-token.mdx Outdated
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Comment thread docs/tokens/shielded-token.mdx
Comment thread docs/tokens/shielded-token.mdx Outdated
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Comment thread docs/tokens/shielded-token.mdx
Co-authored-by: Emmanuel Ameh <oduameh@gmail.com>
Signed-off-by: Idris Olubisi <heedris2olubisi@gmail.com>
Comment thread docs/tokens/shielded-token.mdx
Comment thread docs/tokens/shielded-token.mdx
…eld name

- Reframe the unshielded tutorial's intro as part one of a pair and link
  the companion shielded tutorial, instead of claiming it covers both.
- Use mt_index (snake_case) consistently for the QualifiedShieldedCoinInfo
  Merkle index field. Verified by compiling against the Compact stdlib
  (compact 0.4.0, lang 0.23) and confirmed in upstream source
  (LFDT-Minokawa/compact standard-library.compact); the camelCase mtIndex
  belongs to the separate QualifiedDustOutput type.
- Repoint the renamed 'Go further' section anchor.
Comment thread docs/tokens/unshielded-token.mdx
- Note that sendImmediateShielded returns ShieldedSendResult (same as
  sendShielded); the circuit ignores it because it sends the full value,
  but a partial send returns a change coin to handle.
- Remove all em dashes from the token tutorials, replacing them with
  commas, colons, semicolons, and periods.

The ownPublicKey() authorization caveat is left as-is: verified against
the compiler runtime (runtime/src/zswap.ts returns the prover's local
ZswapLocalState.coinPublicKey) and the compiler changelog, which both
classify ownPublicKey as a witness-like external value, not bound to the
transaction signer.
Match customProps.description to the generated-index description so the
two no longer diverge.
The generated-index default permalink is /category/<name>, which left
/tokens returning 404 (it previously served the hand-authored index).
Pin the generated index to slug: /tokens so the URL keeps working.
@Olanetsoft

Copy link
Copy Markdown
Contributor Author

Source-verified technical review. Every Compact standard library claim was checked against the actual source at LFDT-Minokawa/compact/compiler/standard-library.compact.

All function signatures confirmed (mintUnshieldedToken, sendUnshielded, unshieldedBalanceGte, mintShieldedToken, sendShielded, sendImmediateShielded, evolveNonce, shieldedBurnAddress, pad, persistentHash, all Either type wrapping). One field name discrepancy and two protocol-level claims that cannot be verified from the standard library source are flagged below.

Structural notes:

  • The shielded tutorial's deploy script duplicates ~160 lines of wallet-funding flow from the unshielded tutorial. The PR notes this is intentional ("included here in full so it runs on its own"), but it creates a maintenance burden. Consider a collapsible block or partial.
  • Renaming index.mdx to overview.mdx and switching to generated-index changes the URL from /tokens to /tokens/overview. Any existing links to /tokens now land on the auto-generated index page. Flagged inline on _category_.yaml.

4 suggestions, 7 comments across 3 files.

All fixed. For the snippet that seem to be verbatim, its intentional. Managing should be easy because update to tokens should cover both shielded and unshielded.

node: 'https://rpc.preview.midnight.network',
nodeWS: 'wss://rpc.preview.midnight.network',
proofServer: process.env['MIDNIGHT_PROOF_SERVER'] ?? 'http://127.0.0.1:6300',
faucet: 'https://faucet.preview.midnight.network/api/drips',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the faucet links that are being deprecated -- please update to nethermind faucets

right<ContractAddress, UserAddress>(disclose(recipient))
);
}
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This circuit either needs auth or needs a warning that anyone can call this and drain it to any address they like.

While this tutorial is about Tokens specifically, it would be too easy for a human (or an AI) to copy and paste this code assuming that it is safe. My preference would be to add auth as if this were a real token, rather than having this all be permissionless

);
```

`withVacantWitnesses` applies because the contract has no witnesses; its state is entirely public. `zkConfigPath` points the proof server at the keys the compiler generated under `src/managed/unshielded-token`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Witness !== private state

} else {
logger.info('NIGHT is already registered for DUST generation.');
}
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this checking for a NIGHT UTxO specifically? This crashes on a re-run with a wallet that already holds the test token. Likely because this is taking any UTxO instead of filtering for NIGHT first


## How tokens work on Midnight

Midnight has no native token live on the network yet. NIGHT exists on Cardano and bridges to Midnight later. Until that lands, a smart contract creates every token on Midnight, which is exactly what you do here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only true for mainnet. The tests below demonstrate working with NIGHT on other networks.


You reuse the unshielded tutorial's environment. In particular:

- The toolchain (compactc 0.31.0), the local network (midnight-local-dev), and the proof server. See the [project setup](/tokens/unshielded-token#set-up-your-project).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't recommend this version due to the security flaw -- should be 0.31.1

.update('tutorial:shielded:token:seed')
.digest(),
minterSecret: Uint8Array = createHash('sha256')
.update('tutorial:shielded:minter:secret')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the high likelihood of a user (or AI) copy / pasting this code, we should avoid printing secrets or seeds like this. Other examples call randomBytes(32)

}
```

Unlike the unshielded tutorial, the private state is not empty. It carries the nonce seed. You pass the real value at deploy time in the next step.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It carries the nonce seed and minter secret


On the local network the genesis wallet is already funded and registered, so the NIGHT wait returns immediately, registration reports it is already done, and DUST appears within a few seconds.

Now the shielded-specific part. Build the providers, deploy the contract with the nonce-seed private state, and read the initial state:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Now the shielded-specific part. Build the providers, deploy the contract with the nonce-seed private state, and read the initial state:
Now the shielded-specific part. Build the providers, deploy the contract with the private state, and read the initial state:

logger.info(`initialized at deploy: ${(await readLedger()).initialized}`); // false
```

The one difference from the unshielded tutorial is `initialPrivateState` instead of `{}`: you pass `createShieldedTokenPrivateState()`, which seeds the witnesses.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't seed the witnesses, it populates the private state. Witness !== private state. In this case, the witnesses are just off-chain functions being used to access the private state.

This is not entirely necessary, but offers one example with witnesses and one without. We need to be more clear about the purpose and power of witness functions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants