Skip to content

Examples audit: restructure for docs integration (educational assessment) #1347

@marc0olo

Description

@marc0olo

This issue captures a full educational audit of every example in this repository, conducted to determine what to keep, refocus, or remove in preparation for referencing examples from dfinity/developer-docs.

Every verdict is based on reading the actual source code, not just READMEs. The focus is educational and structural value only. Tooling migrations (dfx → icp-cli) are tracked separately.

The docs integration mapping at the bottom supersedes the aspirational mapping in developer-docs#44 and can be used to drive Phase 2 of that work (adding // #region markers).


Quick-reference verdict table

Example Verdict
hosting/godot-html5-template Keep
hosting/my_crypto_blog Remove
hosting/oisy-signer-demo Keep
hosting/photo-storage Keep but refocus
hosting/react Keep
hosting/static-website Keep
hosting/unity-webgl-template Keep
native-apps/unity_ii_deeplink Keep but refocus (consolidate)
native-apps/unity_ii_applink Remove (merge into deeplink)
native-apps/unity_ii_universallink Remove (merge into deeplink)
svelte/svelte-motoko-starter Keep but refocus
svelte/sveltekit-starter Keep but refocus
wasm/counter Keep
motoko/backend_only Keep but refocus
motoko/basic_bitcoin Keep
motoko/canister_factory Keep
motoko/canister_logs Keep
motoko/cert-var Keep but refocus
motoko/classes Keep
motoko/composite_query Keep
motoko/daily_planner Keep but refocus
motoko/encrypted-notes-dapp-vetkd Remove
motoko/evm_block_explorer Keep
motoko/filevault Keep
motoko/flying_ninja Keep
motoko/hello_cycles Keep
motoko/hello_world Keep
motoko/ic-pos Keep but refocus
motoko/icp_transfer Keep but refocus
motoko/icrc2-swap Keep
motoko/llm_chatbot Keep
motoko/low_wasm_memory Keep
motoko/nft-creator Remove
motoko/parallel_calls Keep
motoko/pub-sub Keep
motoko/query_stats Keep
motoko/random_maze Keep but refocus
motoko/send_http_get Keep
motoko/send_http_post Keep
motoko/superheroes Keep
motoko/threshold-ecdsa Keep
motoko/threshold-schnorr Keep
motoko/token_transfer Remove (consolidated into icrc_ledger)
motoko/token_transfer_from Remove (consolidated into icrc_ledger)
motoko/tokenmania Remove
motoko/vetkd Keep but refocus
motoko/vetkeys Remove
motoko/who_am_i Keep
rust/backend_only Keep
rust/backend_wasm64 Keep but refocus
rust/basic_bitcoin Keep
rust/basic_dogecoin Remove
rust/basic_ethereum Keep
rust/basic_solana Remove
rust/candid_type_generation Keep but refocus
rust/canister-info Keep
rust/canister-snapshot-download Keep but refocus
rust/canister-snapshots Keep
rust/canister_logs Keep
rust/composite_query Keep but refocus
rust/daily_planner Keep
rust/encrypted-notes-dapp-vetkd Remove
rust/evm_block_explorer Keep but refocus
rust/exchange-rates Keep
rust/face-recognition Keep but refocus
rust/flying_ninja Keep
rust/guards Keep
rust/hello_world Keep but refocus
rust/icp_transfer Keep but refocus
rust/image-classification Keep
rust/inter-canister-calls Keep
rust/llm_chatbot Keep
rust/low_wasm_memory Keep
rust/parallel_calls Keep
rust/performance_counters Keep
rust/periodic_tasks Keep
rust/photo_gallery Keep but refocus
rust/qrcode Keep
rust/query_stats Keep
rust/receiving-icp Keep
rust/send_http_get Keep
rust/send_http_post Keep
rust/simd Keep
rust/stake_neuron_from_cli Keep but refocus
rust/threshold-ecdsa Keep
rust/threshold-schnorr Keep
rust/token_transfer Remove (consolidated into icrc_ledger)
rust/token_transfer_from Remove (consolidated into icrc_ledger)
rust/tokenmania Remove
rust/unit_testable_rust_canister Keep
rust/vetkd Keep
rust/vetkeys/basic_bls_signing Keep
rust/vetkeys/basic_ibe Keep
rust/vetkeys/basic_timelock_ibe Keep but refocus
rust/vetkeys/encrypted_chat Remove
rust/vetkeys/encrypted_notes_dapp_vetkd Keep but refocus
rust/vetkeys/password_manager Keep
rust/vetkeys/password_manager_with_metadata Keep
rust/who_am_i Keep
rust/x509 Keep

Counts: Remove 16 | Keep but refocus 23 | Keep 61


REMOVE (16)

Stub redirects with no local source code (5)

These directories contain only a README pointing somewhere else. They add navigation confusion and no educational value. Docs can link to the target repos directly.

motoko/encrypted-notes-dapp-vetkd — Points to dfinity/vetkeys. The real example lives at rust/vetkeys/encrypted_notes_dapp_vetkd. No source here.

motoko/vetkeys — Points to ../../rust/vetkeys/. No source here. Confusing because Motoko backends for vetkeys examples actually exist inside rust/vetkeys/*/motoko/ subdirectories.

rust/encrypted-notes-dapp-vetkd — Points to dfinity/vetkeys. Same as motoko stub above.

rust/basic_dogecoin — Points to dfinity/dogecoin-canister. No source here.

rust/basic_solana — Points to dfinity/sol-rpc-canister. No source here.

Two hosting examples that should consolidate into one (2)

native-apps/unity_ii_applink — The delegation chain architecture (the actual teaching content) is byte-for-byte identical to unity_ii_deeplink. The only difference is the return URL (HTTPS instead of a custom scheme) and one Android manifest intent filter change. This is a variant of deeplink, not a separate concept. Should be a section in a consolidated native-apps example.

native-apps/unity_ii_universallink — Same as above, for iOS. The unique content is a CFBundleURLTypes plist patch and an Apple App Site Association file. Again, a variant of deeplink worth documenting as a platform section rather than a top-level example.

Research prototype mislabeled as a teaching example (1)

rust/vetkeys/encrypted_chat — 1,500+ lines across Rust + Svelte + TypeScript. The README carries an explicit "Disclaimer: This is an unfinished prototype. DO NOT USE IN PRODUCTION." It has an active copy-paste bug in the resharing context function. It is not in the top-level vetkeys README. The vetKey API calls inside it (vetkd_derive_key, vetkd_public_key) are identical to basic_ibe — nothing new is shown at the protocol level. A developer opening this to learn vetKeys will be overwhelmed without gaining anything that basic_ibe doesn't already teach. Its presence in the examples repo as a sibling of the teaching examples sets wrong expectations.

Token examples consolidated into icrc_ledger (6)

motoko/token_transfer, rust/token_transfer — Thin wrappers around icrc1_transfer. The entire example is a single function. This granularity only made sense before a comprehensive icrc_ledger example existed. As regions inside icrc_ledger, the same snippet is available without a separate project.

motoko/token_transfer_from, rust/token_transfer_from — Same reasoning. icrc2_approve + icrc2_transfer_from become regions in icrc_ledger.

motoko/tokenmania, rust/tokenmania — A from-scratch ICRC-1/2 ledger implementation. Teaching developers to implement their own token ledger is the wrong lesson. They should deploy the official icrc1_ledger_canister and interact with it. The reference-implementation framing has no guide to back it up. Remove.


NFT example with no guide home (1)

motoko/nft-creator — Uses mo:icrc7-mo which depends on mo:base (already a signal it's not current). More importantly, NFTs as a concept are not where ICP's differentiation lies — the brand is moving away from crypto-era positioning toward sovereign infrastructure, tamperproof apps, and AI. ICRC-7 is a valid standard, but there is no guide in the docs it maps to, and "how to wire up an NFT library" teaches nothing about ICP specifically. No guide, no brand alignment, stale dependencies.


My_crypto_blog (1)

hosting/my_crypto_blog — Fetches posts from jsonplaceholder.typicode.com (a throwaway test API), calls the app a "crypto blog," and deploys it as a React asset canister. The icp.yaml is byte-for-byte identical to hosting/react. The additional complexity (fetch + loading state + error handling) adds noise rather than ICP-specific knowledge. The name and the centralized API call together create confusion, not clarity. hosting/react covers the same concept better.


KEEP, but refocus (23)

These have real educational value but something specific reduces their usefulness. The "what to fix" is actionable.


hosting/photo-storage

Teaches: Programmatic asset uploads via AssetManager.batch() from @icp-sdk/canisters/assets — including batch semantics, progress callbacks, and chunk handling. Unique concept not covered elsewhere.
Problem: The hardcoded identity is acknowledged as a placeholder but left unresolved. An example that says "replace this before mainnet" teaches an incomplete pattern.
Fix: Wire up Internet Identity for the upload authorization. Then this becomes the canonical "programmatic asset canister upload" reference.


native-apps/unity_ii_deeplink

Teaches: The delegation chain bridge between Internet Identity (browser) and a native mobile app: intermediate ECDSA key creation, chaining a second delegation from that key to the app's Ed25519 public key, and passing the DelegationChain back via a deep link. Non-trivial and correctly implemented.
Problem: Three near-identical examples (deeplink, applink, universallink) obscure the core concept in platform boilerplate. A developer needs to read all three to understand what's different.
Fix: Make unity_ii_deeplink the root example. Add sections for "Android App Links (HTTPS verified)" and "iOS Universal Links" as documented variants within the same example, not separate top-level directories. Remove the other two as standalone examples.


svelte/svelte-motoko-starter

Teaches: II authentication in a Svelte + Motoko app — AuthClient.create()login()getIdentity() → actor creation with that identity → whoami() call. Clean pattern, correct concept.
Problem: Uses @dfinity/auth-client and @dfinity/agent (the deprecated ICP SDK). The teaching point is correct but the API surface is outdated.
Fix: Update to @icp-sdk/auth and @icp-sdk/core/agent. The conceptual structure stays identical; only the imports change.


svelte/sveltekit-starter

Teaches: How to call a Motoko canister from SvelteKit using auto-generated Candid actor declarations — createActor(canisterId, { agent }), actor.greet(input). Clear pattern for any JS framework.
Problem: Uses @dfinity/agent for the actor. Same SDK staleness as above.
Fix: Update to @icp-sdk/core/agent and @icp-sdk/core/actor. The pattern is sound.


motoko/backend_only

Teaches: A minimal persistent actor with a mutable greeting variable, one update and one query function — state that survives upgrades.
Problem: Both backend_only and hello_world are minimal backend examples. The distinction between them (stateful with persistence vs. stateless) is not surfaced in either name or description. Developers don't know which to start with.
Fix: Rename to persistent_greeting or similar, or add a clear note that this is "hello world with mutable state" to differentiate it from the truly minimal hello_world. The persistent keyword and its upgrade-safety semantics should be the headline.


motoko/cert-var

Teaches: Certified variables — CertifiedData.set() and CertifiedData.getCertificate() — so query responses can be cryptographically verified by clients without an update call. Important and unique concept.
Problem: A manual blobOfNat32 byte-encoding helper (15+ lines of bit twiddling) is the first thing you read. It drowns out the 3-line CertifiedData API usage. Old webpack frontend.
Fix: Replace the manual encoding with Text.encodeUtf8("42") or similar so the CertifiedData API is front and center. Modernize the frontend.


motoko/daily_planner

Teaches: Data persistence with mo:map/Map + HTTPS outcalls with transform function in one realistic application.
Problem: Mixes three distinct concepts (CRUD data management, HTTPS outcalls, JSON parsing) in one file. Good as an integration example but not citable as a reference for any single concept. Contains a dead URL (internetcomputer.org/docs/current/...).
Fix: Fix the dead URL. Clearly position this as an integration example ("see send_http_get for HTTPS outcalls in isolation"). The code itself is fine.


motoko/ic-pos

Teaches: Multiple valuable patterns: timer-based ckBTC ledger polling (the most instructive piece), per-merchant data isolation, owner-only access control, and HTTPS outcalls for notifications.
Problem: All four concepts are mixed in 213 lines of application code. The timer-based polling pattern is buried. One HTTPS outcall uses transform = null which is incorrect practice for replicated mode.
Fix: Fix the missing transform function. Add comments that explicitly call out each of the four patterns by name so developers can navigate to the concept they need. Consider whether this should become the canonical "monitoring an ICRC ledger" example.


motoko/icp_transfer

Teaches: Transferring ICP using the legacy ICP ledger API — TransferArgs with AccountIdentifier, Tokens in e8s, Memo.
Problem: Developers may not realize this uses a legacy API. The ICP ledger supports ICRC-1 now, and icrc_ledger is the modern equivalent. Without a clear note, a developer might choose this as their starting point when they should use icrc_ledger.
Fix: Add a prominent README note: "This uses the legacy ICP ledger API (account-identifier based). For new code, prefer icrc_ledger (ICRC-1). Use this if you're integrating with exchanges or existing infrastructure that uses account identifiers."


motoko/random_maze

Teaches: Random.crypto() for async cryptographic entropy on ICP, await* random.natRange(0, n) for bounded integers, and AsyncRandom usage in general.
Problem: The actual ICP-relevant concept (the AsyncRandom API) is buried inside a moderately complex maze generation algorithm with bit-masking for wall/visited state tracking. A developer searching for "how to use ICP randomness" may not see the signal through the maze logic.
Fix: Add a prominent comment block early in the file: "The ICP-specific pattern is in lines X–Y: Random.crypto() creates an async random source backed by the management canister. Everything else is maze-generation algorithm." Or extract the randomness into a simpler companion example.


motoko/vetkd

Teaches: The management canister vetKD API directly — vetkd_public_key and vetkd_derive_key for both "symmetric_key" and "ibe_encryption" contexts. 74 lines, both use cases side by side.
Problem: The naming confusion between vetkd, vetkeys, and the vetkeys examples is significant. Two empty stub directories (motoko/vetkeys, motoko/encrypted-notes-dapp-vetkd) point to rust/vetkeys/*/motoko/ backends, but this standalone motoko/vetkd is unrelated to those. A developer exploring vetKeys will hit three directories and not understand the landscape.
Fix: Remove the two stubs (done per Remove section). Keep motoko/vetkd as the minimal Motoko vetKD reference. Add a clear README note: "This is the minimal backend API example. For complete applications using vetKeys, see rust/vetkeys/."


rust/backend_wasm64

Teaches: That ICP supports Wasm64, enabling canisters to address more than 4GB of memory.
Problem: The Rust source is identical to backend_only. The teaching is entirely in the Cargo.toml target and build configuration, which is easy to miss.
Fix: Add a comment in lib.rs and a clear README: "This is backend_only compiled to the wasm64-unknown-unknown target. The source code is intentionally identical — the only difference is in Cargo.toml. Wasm64 enables memory addressing beyond 4GB."


rust/candid_type_generation

Teaches: Using ic-cdk-bindgen in build.rs to auto-generate Rust types from a Candid .did file, eliminating manual type duplication.
Problem: The example bundles the build script pattern (the unique concept) with NNS governance inter-canister calls (a large, complex secondary concern). The two are separable.
Fix: The build script pattern is the unique educational value. Consider whether the NNS governance call is the right downstream to demonstrate it against, or whether a simpler canister interface would be clearer. At minimum, the README should make the build script pattern the headline.


rust/canister-snapshot-download

Teaches: A scenario where stable memory is corrupted (represented by the minimal raw stable memory read/write canister), and how to download a snapshot, modify it, and re-upload to fix the corruption.
Problem: The canister code itself (lib.rs, 21 lines) is a trivial stable memory demo without context. The teaching is in the surrounding scripts and docs. A developer reading lib.rs learns almost nothing about snapshots.
Fix: Add inline comments explaining what this canister is demonstrating and why the stable memory layout matters for the snapshot scenario. Consider merging with canister-snapshots into one coherent "canister lifecycle: snapshot and restore" example.


rust/composite_query

Teaches: The #[query(composite = true)] attribute for making inter-canister calls from a query context — reduces latency significantly for read-heavy multi-canister architectures.
Problem: The example embeds a canister factory pattern (creating and installing partition canisters from Wasm bytes at runtime) alongside the composite query pattern. The two concepts are orthogonal, and the factory code adds complexity that distracts from the composite query point.
Fix: Strip or move the canister factory logic. Keep only the partition canister pattern needed to demonstrate composite = true. The get vs get_update comparison is excellent and should be front and center.


rust/evm_block_explorer

Teaches (should be): Querying Ethereum block data via the EVM RPC canister, handling multi-provider consensus results (#Consistent(#Ok), #Consistent(#Err), #Inconsistent).
Problem: The example also includes sign_message_with_ecdsa and sign_message_with_schnorr functions that have nothing to do with block exploration. The scope is incoherent — it's a block explorer and a key demo simultaneously.
Fix: Remove or extract the signing functions. Keep only the block fetching and the three-way consensus result handling. The name should match the concept: this is about eth_get_block_by_number and multi-provider result handling.


rust/face-recognition

Teaches: Running ONNX neural network inference on ICP via ic_wasi_polyfill (WASI compatibility layer inside a canister), loading large model binaries in chunks via stable memory.
Problem: The chunked model upload and WASI polyfill patterns are the ICP-specific teaching points, but they are buried under two ONNX model pipelines and the ML inference code. Developers building AI apps need to extract the infra patterns from the ML logic.
Fix: Add a dedicated comment section (or README section) explicitly naming the ICP-specific patterns: "1. How chunked stable memory upload works (lines X–Y). 2. How ic_wasi_polyfill::init() provides WASI compatibility (line Z)."


rust/hello_world

Teaches: Persisting a greeting prefix in a StableBTreeMap Cell via MemoryManager, exposing a set_greeting update and greet query.
Problem: The name says "hello world" but the code teaches stable memory persistence with ic_stable_structures. backend_only is the actual hello world (4 lines, one query). A new developer opening hello_world expecting an entry point gets an intermediate stable-memory lesson.
Fix: Rename to persistent_greeting or stable_memory_greeting. Make backend_only the primary entry point. Or explicitly add a README note: "This example teaches stable memory, not hello world. For the minimal starting point, see backend_only."


rust/icp_transfer

Teaches: Transferring ICP using the legacy ic_ledger_types crate — AccountIdentifier, Tokens, transfer().
Problem: Same issue as motoko/icp_transfer. The legacy API is correct for some use cases (exchange integrations, existing infrastructure) but should not be the first thing developers reach for.
Fix: Add a prominent README note distinguishing legacy vs ICRC-1. Cross-link to icrc_ledger.


rust/photo_gallery

Teaches: Implementing the http_request query handler to serve binary content (images) from canister memory with cache headers via the HTTP gateway.
Problem: Uses add_skip_certification_header, which opts out of asset certification entirely. This is the lazy path and is not safe for production. There is no explanation of the tradeoff.
Fix: Add a comment explaining the skip-certification choice: "This example uses skip_certification for simplicity. In production, implement certified assets to cryptographically verify responses." Link to certified-variables guide or the asset canister pattern.


rust/stake_neuron_from_cli

Teaches: Programmatic NNS neuron staking from Rust using ic-agent — computing the staking subaccount hash (SHA-256 with domain separation), building a principal-signed agent, calling governance.
Problem: This is a Rust CLI binary using ic-agent, not a canister. It is in a fundamentally different category from every other Rust example in the directory. Developers browsing canister examples will be confused when they find a CLI tool.
Fix: Add a clear README header: "This is a Rust CLI program, not a canister. It demonstrates how to use ic-agent for programmatic interaction with an ICP canister from outside the IC." It is valuable in that category, just mislabeled.


rust/vetkeys/basic_timelock_ibe

Teaches: Canister-side decryption at a timed event — a canister holds its own transport key and uses a timer to trigger IBE key derivation and batch decryption of submitted ciphertexts. This is distinct from client-side decryption in basic_ibe.
Problem: The auction application scaffolding (lot status machines, bid tracking, tie-breaking logic) is ~350 lines around a ~50-line crypto core. The key pattern — a canister acting as its own decrypter — is buried. The dummy vec![0; 32] transport key seed looks alarming without a comment explaining it is safe here (per-call ephemeral transport key).
Fix: Add a comment explaining the dummy seed and why it's safe. Reduce the auction scaffolding or add explicit navigation comments pointing to the decrypt_ciphertexts() function as "the core teaching content."


rust/vetkeys/encrypted_notes_dapp_vetkd

Teaches: Per-resource symmetric key derivation using vetKeys: the note ID (not user principal) is the key derivation input, so the same key is accessible to any authorized user of that note. Also: caching non-extractable AES keys in IndexedDB — the only example in the set showing this pattern.
Problem: The Motoko backend uses mo:base (deprecated) and preupgrade/postupgrade hooks (old pattern). This makes it a bad Motoko reference even though the concept is sound.
Fix: Migrate Motoko backend to mo:core and persistent actor. The JavaScript pattern (IndexedDB caching of non-extractable keys) is genuinely unique and should be highlighted in the README.


KEEP (61)

These examples teach something distinct and do it well enough to reference from docs.


hosting/

godot-html5-template — Teaches: any pre-built static output (here: a Godot HTML5 export) can be deployed to ICP via an asset canister with a four-line config. Serves game developers who want confirmation their engine output works on ICP.

oisy-signer-demo — Teaches: the full ICRC signer standard (ICRC-29) flow — creating a Signer with PostMessageTransport, wrapping an HttpAgent in a SignerAgent for signed transactions, using anonymous agents for reads (no popup) and signer agents for writes (wallet popup). The useOisyWallet.js hook is well-commented production-quality code. Only example covering wallet integration standards.

hosting/react — Teaches: React/Vite app deployed as an ICP asset canister. The entire concept is in the icp.yaml. Correctly minimal.

hosting/static-website — Teaches: pure HTML/CSS/JS files deployed to ICP without any build tool. The no-Node-toolchain path is distinct from react and matters for developers not using a JS framework.

hosting/unity-webgl-template — Same concept as godot-html5-template but for Unity — the most widely used game engine. Distinct audience justifies a separate example despite structural similarity.


wasm/

wasm/counter — The best-written example in the entire collection from a pure educational standpoint. 106 lines of commented .wat demonstrating: IC System API imports (msg_reply, msg_reply_data_append, msg_arg_data_size, msg_arg_data_copy), the canister_query / canister_update export naming convention, manual Candid encoding with documented byte layout, and memory management. After reading this, a developer understands what Motoko and Rust CDKs are doing on their behalf. Irreplaceable as a System API reference.


motoko/

hello_world — Simplest possible entry point. Every platform needs a true hello world. Teach persistent actor + one query function. Keep as the "step 1."

who_am_i — 7 lines. Teaches public query (message) func and message.caller — the foundation of all access control on ICP. Essential for every developer.

canister_logs — Teaches: Debug.print behavior across update/query/timer contexts, intentional traps, and the difference between pre-trap logging and post-trap recovery. Each public function isolates one scenario.

classes — Teaches: actor classes as instantiatable canister blueprints, the with cycles syntax, and sharded state distribution across dynamically created canisters. Foundational for multi-canister architecture.

composite_query — Teaches: public composite query func for calling other canisters' query functions without consensus. The side-by-side getUpdate vs get (composite query) contrast makes the latency benefit concrete. Covers a distinct, non-obvious ICP capability.

canister_factory — Teaches: the four actor class lifecycle modes (#new, #install, #upgrade, #reinstall) and when to use actor class management vs. management canister calls directly. Includes before/after state comparisons for upgrade vs. reinstall. Uniquely comprehensive canister lifecycle reference.

evm_block_explorer — Teaches: EvmRpc.eth_getBlockByNumber and the three-way result type (#Consistent(#Ok), #Consistent(#Err), #Inconsistent) for multi-provider consensus. Good chain-fusion reference combining EVM RPC with ECDSA/Schnorr.

filevault — Teaches: per-principal data isolation using nested Map (principal → filename → blob chunks), chunked blob upload/retrieve. The principal-scoped pattern is fundamental to ICP security and is not as clearly shown in other examples.

flying_ninja — Teaches: in-memory sorted leaderboard, bounded array with insert-sort, and Random.blob() for client seeds. Concrete and relatable.

hello_cycles — Teaches: Cycles.balance(), Cycles.available() / Cycles.accept() for capping incoming cycles, and with cycles = amount + Cycles.refunded() for forwarding. The canonical cycles mechanics reference — no other example explains acceptance and forwarding this clearly.

icrc2-swap — The best security-focused example in the collection. Teaches: the deposit-swap-withdraw pattern, why the swap itself must be await-free for atomicity, and why withdrawal must debit-before-transfer (not the reverse) to prevent reentrancy. The inline comments explaining these design decisions are exceptional and rare in example code.

llm_chatbot — Teaches: both LLM.prompt() (single-turn) and LLM.chat() (multi-turn with message history) from mo:llm. 16 lines. On-chain AI is a differentiating ICP capability.

low_wasm_memory — Teaches: system func lowmemory() hook for proactive memory pressure handling before an OOM trap. No other example covers this operational resilience pattern.

parallel_calls — Teaches the critical ICP async performance pattern: fire all calls first, collect futures, then await them all (not await in a loop). The sequential vs. parallel contrast makes the difference concrete. The comment about calls failing under high load is an important practical note.

pub-sub — Teaches: passing and storing shared func references as inter-canister callbacks — idiomatic Motoko that enables pub-sub patterns without polling. The callback-as-field pattern is non-obvious and not demonstrated elsewhere.

query_stats — Teaches: canister_statusquery_stats for runtime observability. Short, focused, unique topic.

send_http_get — The canonical HTTPS GET outcall reference. Teaches: transform function pattern, max_response_bytes with cost explanation, is_replicated = ?true for consensus, and cycle attachment. Inline comments are outstanding. #region markers make it doc-ready.

send_http_post — Companion to send_http_get. Adds: request body encoding, Content-Type header, is_replicated = ?false for non-replicated mode with idempotency key explanation. The GET/POST split is justified because the replicated/non-replicated semantics differ.

superheroes — The canonical CRUD reference. Create/read/update/delete on a Map with auto-incrementing IDs. Query vs. update distinction. Clean, 39 lines.

threshold-ecdsa — Canonical threshold ECDSA reference. Teaches: ecdsa_public_key and sign_with_ecdsa management canister calls, the three key ID environments (local/test/production), and SHA-256 pre-hashing. Essential for any chain-key signing use case.

threshold-schnorr — Canonical threshold Schnorr reference. Teaches both BIP340 (secp256k1, Bitcoin Taproot) and Ed25519 variants. BIP-341 taproot tweak is correctly isolated.

basic_bitcoin — Definitive Bitcoin integration reference. Teaches: P2PKH / P2WPKH / P2TR address derivation, UTXO management, fee estimation via percentiles, iterative transaction construction for P2TR Taproot. The Bitcoin-specific complexity is inherent to the domain, not bad code. Correctly labeled advanced.


rust/

backend_only — Correct hello world for Rust. Four lines, one query. The entry point.

basic_bitcoin — Same assessment as motoko: definitive Bitcoin wallet reference, comprehensive, appropriately advanced.

basic_ethereum — Teaches: ECDSA key derivation per principal, Ethereum address computation from secp256k1 public key, EIP-1559 transaction construction and signing via alloy, single-provider vs. multi-provider broadcast. Complete Ethereum wallet pattern.

canister-info — Teaches: canister_info management canister API for retrieving canister change history, controller hierarchies, and deployment chain traversal. Unique observability patterns not covered elsewhere.

canister-snapshots — Teaches: the value of snapshots via a creative approach — the canister has a deliberate, commented-and-flagged bug in remove_spam. After taking a snapshot, deploying the buggy upgrade, and observing the broken state, restoring the snapshot demonstrates the concept clearly. Memorable because of the intentional bug.

canister_logs — Teaches: ic_cdk::print, println!, trap in update/query/timer contexts. Covers all log production paths.

daily_planner — Good multi-concept integration example combining StableBTreeMap with custom Storable (Candid-serialized), HTTPS outcalls with transform, and CRUD. Realistic application that shows how the pieces connect.

exchange-rates — Teaches: calling the IC Exchange Rate Canister with Call::bounded_wait, attaching cycles, and decoding a typed response. Clean and focused.

flying_ninja — Same as Motoko: concrete game leaderboard with sorted in-memory state and raw_rand() usage.

guards — Essential security example. Teaches: RAII-based reentrancy prevention via Drop-based guard, and the critical nuance that the guard is only effective across await points (not within a synchronous message). The comment explaining TrueAsyncCall vs FalseAsyncCall (poll-to-completion vs yield) is one of the best educational comments in the entire library.

image-classification — Simpler ONNX entry point than face-recognition. Teaches: loading an ONNX model at init/post_upgrade, ic_wasi_polyfill::init() for WASI compatibility. Good first example for on-canister ML.

inter-canister-calls — Outstanding quality. Teaches: Call::unbounded_wait vs bounded_wait, with_arg, typed decoding, is_clean_reject() / is_immediately_retryable() error handling, retry-with-deadline pattern (stubborn_set), and cycle attachment. Each function in the caller canister teaches one distinct aspect. The comments about messaging model nuances are developer-essential material.

llm_chatbot — 20 lines, ic_llm crate, both prompt (single-turn) and chat (multi-turn). The simplest possible LLM entry point.

low_wasm_memory — Teaches #[on_low_wasm_memory] hook. Fix the stale "Bitcoin canister" comment but keep otherwise.

parallel_callsfuture::join_all for concurrent inter-canister calls. The practical failure note under high load is important.

performance_counters — Teaches: instruction_counter() and call_context_instruction_counter() across await boundaries and in composite queries. Side-by-side comparison of counter behavior is unique.

periodic_tasks — Teaches: set_timer_interval (recommended) vs #[heartbeat] (legacy) with identical logic so the tradeoffs are directly comparable. The heartbeat limitations note is correct and useful.

qrcode — Teaches: CPU-intensive computation (QR code generation + PNG rendering + logo overlay) in a canister is viable. Both update and query endpoints. performance_counter(0) logging is a bonus.

query_stats — Unique monitoring pattern: query stats from canister_status.

receiving-icp — Teaches: computing a canister's AccountIdentifier and subaccounts, querying ICP balance. Practical complement to icp_transfer.

send_http_get and send_http_post — Among the best-written examples in the collection. Both referenced under Motoko assessment — same high marks apply.

simd — Teaches: Wasm SIMD128 in a Rust canister — naive, packed, auto-vectorized, and explicit SIMD implementations side by side with instruction_counter() benchmarking. Essential for ML/compute-intensive developers.

threshold-ecdsa — Canonical minimal threshold ECDSA reference for Rust. Key ID enum with three environment variants is the correct pattern.

threshold-schnorr — Canonical Schnorr reference for Rust. BIP341 Tapscript correctly isolated in wasm_only.rs. Includes integration tests.

unit_testable_rust_canister — The only example teaching DI-based unit testing for canisters: trait-based mocks, Arc<dyn Trait>, #[tokio::test] for async testing. Every serious Rust canister developer needs this pattern.

vetkd — Minimal vetKeys backend reference: vetkd_public_key and vetkd_derive_key for both symmetric key and IBE contexts. 87 lines, two use cases side by side.

who_am_i — Canonical msg_caller() reference. 10 lines.

x509 — Unique, sophisticated PKI example. Teaches: using threshold ECDSA and Schnorr keys as a Certificate Authority, CSR parsing and signature verification, root + leaf X.509 certificate issuance. Represents a genuinely novel ICP capability. For advanced developers building PKI infrastructure.


rust/vetkeys/

basic_bls_signing — Teaches: sign_with_bls path — per-user BLS12-381 key derivation, domain separator construction, on-chain signature storage, browser-side verification via @dfinity/vetkeys. Only BLS signing example.

basic_ibe — The canonical, teachable IBE reference. Teaches the full round-trip: vetkd_public_keyIbeCiphertext.encrypt(publicKey, IbeIdentity.fromPrincipal(receiver))vetkd_derive_key(transport_key)EncryptedVetKey.decryptAndVerify()IbeCiphertext.decrypt(). The code in main.ts maps one-to-one onto the protocol steps. Every other IBE-using example should link back to this.

password_manager — Teaches: using the EncryptedMaps abstraction from the ic-vetkeys crate as a drop-in encrypted key-value store with access control. The contrast between the thin wrapper here and the raw API in encrypted_notes_dapp_vetkd is the key educational progression.

password_manager_with_metadata — Teaches one specific, real-world pattern: atomically updating an encrypted value (EncryptedMaps) and its unencrypted metadata (StableBTreeMap) in a single update call. The diff vs. password_manager is the entire lesson. Narrow and correct.


Structural observations

The "hello world" problem in Rust: backend_only (4 lines, correct entry point) and hello_world (stable memory with MemoryManager, an intermediate topic) have inverted roles. hello_world should be renamed.

vetKeys example architecture: The 6 examples (after removing encrypted_chat) form a clean three-layer progression that is worth making explicit:

  • Layer 1 — Primitives: basic_ibe, basic_bls_signing
  • Layer 2 — Patterns: encrypted_notes_dapp_vetkd (raw API, resource-keyed), basic_timelock_ibe (canister-as-decrypter)
  • Layer 3 — Abstraction: password_manager, password_manager_with_metadata

Legacy vs. ICRC-1 ICP transfers: icp_transfer (both Motoko and Rust) covers the legacy ICP ledger API; icrc_ledger (to create) covers the ICRC-1 standard. Both are valid but serve different audiences — icp_transfer for exchange/infrastructure integrations, icrc_ledger for new code. They need clear cross-references.

daily_planner in both languages is an integration example that deliberately combines multiple concepts. It serves a different purpose from the focused single-concept examples. Both should be kept and positioned as "see how the pieces fit together."

The evm_block_explorer scope problem appears in both Motoko and Rust: a block explorer that also contains unrelated signing functions. Both need the same fix: remove or extract the signing.

Strongest examples overall (code quality + educational clarity + unique concept): wasm/counter, rust/guards, rust/inter-canister-calls, motoko/icrc2-swap, rust/send_http_get, rust/vetkeys/basic_ibe, motoko/parallel_calls.


Docs integration mapping

This section drives Phase 2 of developer-docs#44: adding // #region markers to examples so the docs pipeline can extract snippets.

Format: Guide → canonical example(s) → suggested region names.
Region names are placeholders — refine during implementation. "Both" means Motoko + Rust versions exist or will be created.

Out of scope for the snippet pipeline (CLI commands, config, Candid spec, tooling guides): canister lifecycle CLI, icp.yaml config, custom domains, reproducible builds, Rosetta API, developer tools.

Getting started

Guide Example Regions
Quickstart hello_world (both) greeting_function, query_call, update_call

Backend development

Guide Example Regions
Data persistence superheroes (both) — rename to data_store create, read, update, delete, stable_state
HTTPS outcalls send_http_get + send_http_post (both) get_request, transform, post_request, cycles_cost
Timers periodic_tasks (both — Mo version to create) recurring_timer, one_shot_timer, post_upgrade_reregister
Onchain randomness Refocused random_maze or new randomness (both) get_entropy, bounded_random, usage_example
Certified variables Refocused cert-var (both — Rs version to create) set_certified, get_with_certificate, verify_client
Onchain AI llm_chatbot (both) simple_prompt, multi_turn_chat

Canister calls

Guide Example Regions
Onchain calls inter-canister-calls (both — Mo version to create) basic_call, bounded_wait, error_handling, retry_pattern
Parallel calls parallel_calls (both) sequential_calls, parallel_calls, join_all
Pub-sub pattern pub-sub (Mo only — Motoko-specific pattern) publisher_register, publisher_publish, subscriber_callback
Offchain calls frontend_agent to create (JS + both) agent_setup, query_call, update_call, auth_delegation

Frontend development

Guide Example Regions
Hosting a React app hosting/react icp_yaml, vite_config
Hosting a static site hosting/static-website icp_yaml
Programmatic asset upload hosting/photo-storage (after II auth added) asset_manager_setup, batch_upload, upload_progress
Response verification rust/photo_gallery (after certification note added) http_request_handler, certified_headers

Authentication

Guide Example Regions
Internet Identity who_am_i (both) ii_login, get_identity, actor_with_identity, whoami_call

Testing

Guide Example Regions
Unit testing (Rust) unit_testable_rust_canister trait_definition, mock_implementation, unit_test
Integration testing / PocketIC New tested_canister (both) pocket_ic_setup, deploy_and_call, state_assertion

Security

Guide Example Regions
Async call safety icrc2-swap (Mo) + guards (Rs) atomic_swap, debit_before_transfer, reentrancy_guard, drop_impl
Canister upgrades canister-snapshots (Rs) pre_upgrade, post_upgrade, snapshot_restore
Access control guards (Rs) + parts of who_am_i caller_check, raii_guard

Note: safe_calls (CallerGuard, saga pattern) and rate_limiter are gaps — no clean example exists yet. Inline snippets in docs for now.

Chain fusion

Guide Example Regions
Bitcoin integration basic_bitcoin (both) generate_address, get_utxos, create_transaction, sign_and_send
Ethereum integration basic_ethereum (Rs) derive_eth_address, get_balance, build_transaction, sign_and_broadcast
EVM block reading Refocused evm_block_explorer (both) eth_get_block, handle_consensus_result
Threshold ECDSA threshold-ecdsa (both) get_public_key, sign_message, verify_signature
Threshold Schnorr threshold-schnorr (both) bip340_sign, ed25519_sign, verify

Token transfers and payments

"DeFi" is banned as a section heading — it is a crypto-era category label, not a technical description. Use precise terms: ICRC-1, ICRC-2, token ledger, payments.

Guide Example Regions
ICRC ledger (deploy + interact) New icrc_ledger (both) — replaces tokenmania, token_transfer, token_transfer_from deploy_ledger, transfer, check_balance, approve, transfer_from
ICP legacy ledger icp_transfer + receiving-icp (both) derive_account_id, transfer_icp, check_balance
Async payment safety icrc2-swap (Mo) deposit, atomic_swap, safe_withdraw
Wallet / signer integration hosting/oisy-signer-demo signer_setup, connect_wallet, signed_transfer, session_persistence

Note: ckbtc_deposit (deposit/withdrawal flow) is a gap — ic-pos shows polling patterns but not the deposit flow in isolation. Create or extract from ic-pos.

Canister management

Guide Example Regions
Canister logs canister_logs (both) debug_print, trap_log, timer_log, query_log
Canister info canister-info (Rs) get_canister_info, controller_history
Snapshots canister-snapshots (Rs) pre_upgrade_state, buggy_upgrade, restore_snapshot
Cycles management hello_cycles (Mo + Rs to create) check_balance, accept_cycles, forward_cycles
Low memory hook low_wasm_memory (both) low_memory_handler, heartbeat_fill
Query stats query_stats (both) get_query_stats
Performance profiling performance_counters (Rs) count_instructions, composite_query_counters
Large Wasm / Wasm64 backend_wasm64 (Rs) wasm64_config (build config, not code)
Wasm optimization / SIMD simd (Rs) naive_matmul, simd_matmul, benchmark

Encryption (vetKeys)

Guide Example Regions
IBE — concept and protocol vetkeys/basic_ibe (both) get_ibe_public_key, encrypt_message, get_decryption_key, decrypt_message
BLS signing vetkeys/basic_bls_signing (both) sign_with_bls, domain_separator, verify_bls
Timelock encryption vetkeys/basic_timelock_ibe (Rs) encrypt_bid, canister_decrypt, timer_reveal
Encrypted storage — raw API vetkeys/encrypted_notes_dapp_vetkd (both, after Mo fix) derive_note_key, store_encrypted, retrieve_and_decrypt
EncryptedMaps usage vetkeys/password_manager (both) init_encrypted_maps, insert_value, grant_access, get_encrypted_key
EncryptedMaps + metadata vetkeys/password_manager_with_metadata (both) insert_with_metadata, atomic_update

Relationship to developer-docs#44

Issue #44 defines the snippet pipeline: region markers in examples → remark plugin → CodeExample component in docs. That pipeline is the right approach and Phase 1 implementation is underway.

This assessment is the prerequisite for Phase 2 (adding region markers). The guide→example mapping above supersedes the aspirational mapping in issue #44. Specifically:

  • tokenmania, token_transfer, and token_transfer_from (all listed in update dfx version so example runs without error #44) are replaced by a single icrc_ledger example with regions. The section is also renamed from "DeFi / tokens" to "Token transfers and payments"
  • evm_block_explorer needs scope fix before region markers are added
  • inter-canister-calls, periodic_tasks, cert-var all have Motoko gaps that must be filled before they can serve as dual-language doc examples
  • Several examples update dfx version so example runs without error #44 planned as "to create" (safe_calls, rate_limiter, safe_upgrades, tested_canister, ckbtc_deposit, sns_governed) are still gaps — docs for those guides should remain inline until examples exist

Recommended sequence:

  1. Restructure the examples repo per this assessment (drop, consolidate, refocus)
  2. Create the missing examples identified above
  3. Add region markers to the canonical set (Phase 2 of update dfx version so example runs without error #44)
  4. Wire up the remark plugin + CodeExample component in docs (Phase 1/3 of update dfx version so example runs without error #44, already in progress)
  5. Migrate guide pages from inline snippets to <CodeExample> components incrementally

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions