Skip to content

Conversation

@tilo-14
Copy link
Collaborator

@tilo-14 tilo-14 commented Jan 17, 2026

Summary

  • Add native program documentation with tabs
  • Add Rust client cookbook examples
  • Update stream toolkit
  • Fix component issues

Test plan

  • Verify all links work
  • Check code examples render correctly
  • Verify program tabs display correctly

Summary by CodeRabbit

  • New Features

    • Added three new Light Token cookbook recipes: Approve & Revoke, Burn, and Freeze/Thaw operations.
    • Enhanced code comparison tool with Rust syntax highlighting and copy functionality.
  • Documentation

    • Reorganized cookbook navigation with improved recipe ordering.
    • Refactored recipe guides with streamlined code examples and external references.
    • Updated token operation terminology for clarity.
  • Chores

    • Added automation scripts for code snippet management.
    • Updated internal API references for consistency.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

Walkthrough

This PR expands the Light Token cookbook with three new recipe guides (burn, freeze-thaw, approve-revoke), reorganizes cookbook navigation order, refactors existing documentation to use modular code samples and external references, updates SDK import paths to reflect renamed public entities (e.g., CloseTokenAccountCpi to CloseAccountCpi), and enhances the CodeCompare component to support Rust syntax highlighting.

Changes

Cohort / File(s) Summary
Navigation & Configuration
docs.json
Updated Recipes group to expand by default; reordered close-token-account after load-ata; added three new recipe entries: burn, freeze-thaw, approve-revoke.
New Cookbook Pages
light-token/cookbook/burn.mdx, light-token/cookbook/freeze-thaw.mdx, light-token/cookbook/approve-revoke.mdx
Three new MDX recipe guides with Rust client examples, code comparisons against SPL, prerequisites, step-by-step instructions, Anchor/Native program guides, full code examples, and Next Steps links.
Refactored Cookbook Pages
light-token/cookbook/create-ata.mdx, light-token/cookbook/create-mint.mdx, light-token/cookbook/create-token-account.mdx, light-token/cookbook/mint-to.mdx, light-token/cookbook/transfer-interface.mdx, light-token/cookbook/close-token-account.mdx, light-token/cookbook/load-ata.mdx, light-token/cookbook/wrap-unwrap.mdx
Replaced inline code blocks with modular CodeCompare components and external references; reorganized Rust/program examples into tabs; refactored code structure from inline to snippet-based; updated Next Steps links and terminology (e.g., "Cold light-tokens" → "Unified Transfer Interface").
Toolkit Documentation
light-token/toolkits/for-streaming-mints.mdx
Updated SDK imports and type signatures: CompressedMintMint, CompressedMintMetadataMintMetadata; refactored struct fields and function signatures to reflect new compressed mint layout.
Code Snippet Generation Scripts
scripts/copy-program-snippets.sh, scripts/copy-rust-snippets.sh
Two new Bash scripts to automate extraction of Rust program snippets and client code from source directories into documentation, with wrapping in Markdown code blocks.
Code Samples
snippets/code-samples/code-compare-snippets.jsx
Added 22 new Rust code exports (paired SPL and Light Token variants) for operations: Transfer, Create ATA, Create Mint, Mint To, Create Token Account, Close, Burn, Freeze, Thaw, Approve, and Revoke.
Snippet Files
snippets/code-snippets/light-token/(burn|freeze-thaw|approve-revoke|...)/(program|rust-client)/*.mdx
Added 50+ new MDX snippet files containing Anchor/Native Solana program examples and Rust client code samples for all new and refactored recipes.
Component Update
snippets/jsx/code-compare.jsx
Enhanced CodeCompare component with Rust syntax highlighting, copy-to-clipboard button, slider UI refinement, and dynamic code display logic based on slider position.
Documentation
snippets/compressible-rent-explained.mdx, snippets/light-token-configure-rent.mdx
Updated SDK type usage from CompressibleParamsInfosCompressibleParamsCpi; refined rent cost documentation with detailed bullet points and tooltips.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

Poem

🐰 Three recipes hopped into the warren,
With snippets refactored and samples sworn in,
From Burn to Freeze, the light tokens now dance,
Organized tabs give code a grand chance—
The cookbook grows richer, one click at a time! 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add native programs and Rust client cookbook' directly and accurately reflects the main changes in this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 15

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
light-token/toolkits/for-streaming-mints.mdx (1)

202-229: Update struct names and remove non-existent fields to match the actual SDK.

The documented structures do not match the light-ctoken-interface SDK. The actual struct names are CompressedMint (not Mint) and CompressedMintMetadata (not MintMetadata). Additionally, the following documented fields do not exist in the SDK and must be removed: reserved, account_type, compression from the Mint struct; mint_signer and bump from MintMetadata. The field mint_decompressed should be spl_mint_initialized. Update the code snippet to reflect the actual SDK definitions.

light-token/cookbook/create-mint.mdx (1)

2-2: Typo in page title.

"wih" should be "with".

✏️ Fix typo
-title: Create Mint Account wih Token Metadata
+title: Create Mint Account with Token Metadata
snippets/jsx/code-compare.jsx (1)

1-351: Run Prettier to fix formatting violations.

This file has 13 lines exceeding the configured 100-character print width and will fail the format:check step in CI. Execute npm run format to resolve.

🤖 Fix all issues with AI agents
In `@light-token/cookbook/burn.mdx`:
- Around line 20-22: The second sentence has a subject-verb agreement error: in
the sentence starting with "Burned tokens are removed from circulation and
decreases the supply tracked on the mint account" change the verb "decreases" to
"decrease" so it agrees with the plural subject "Burned tokens" (i.e., update
the sentence that begins "Burned tokens are removed from circulation..." to use
"decrease the supply tracked on the mint account").

In `@scripts/copy-program-snippets.sh`:
- Around line 6-8: The script uses hardcoded absolute paths (NATIVE_DIR,
ANCHOR_DIR, SNIPPETS_DIR) which breaks portability; change them to computed
relative paths by deriving a base directory (e.g., using the script directory
via BASH_SOURCE or the repository root via git rev-parse --show-toplevel) and
then build NATIVE_DIR, ANCHOR_DIR and SNIPPETS_DIR from that base so the script
works on other machines; update any usages in copy-program-snippets.sh to
reference the new variables.

In `@scripts/copy-rust-snippets.sh`:
- Around line 6-7: The script copy-rust-snippets.sh uses hardcoded absolute
paths in EXAMPLES_DIR and SNIPPETS_DIR which break portability; change these to
either respect environment variables (e.g., read EXAMPLES_DIR and SNIPPETS_DIR
from env with sensible defaults) or compute them relative to the script location
(use the script dirname to build paths) so the variables EXAMPLES_DIR and
SNIPPETS_DIR are not machine-specific and will work in CI and other dev
machines.

In `@snippets/code-samples/code-compare-snippets.jsx`:
- Around line 132-146: The snippet references LIGHT_TOKEN_PROGRAM_ID but only
imports TransferInterface; update the import to bring LIGHT_TOKEN_PROGRAM_ID
into scope (e.g., add LIGHT_TOKEN_PROGRAM_ID to the use statement that currently
imports TransferInterface) so the TransferInterface initialization can set
source_owner and destination_owner to LIGHT_TOKEN_PROGRAM_ID.

In `@snippets/code-snippets/light-token/approve-revoke/program/anchor.mdx`:
- Around line 1-2: The file is a placeholder empty Rust block for the
approve-revoke Anchor program; either replace it with a full Anchor program
implementing approve/revoke handlers or delete the file. To implement, add an
Anchor program module (e.g., #[program] pub mod approve_revoke) with two
exported functions pub fn approve(ctx: Context<Approve>, amount: u64) and pub fn
revoke(ctx: Context<Revoke>) that call the CPI helpers in
anchor_spl::token::approve and anchor_spl::token::revoke, and add corresponding
context structs (struct Approve<'info> { #[account(mut)] source: Account<'info,
TokenAccount>, #[account(signer)] authority: AccountInfo<'info>, token_program:
Program<'info, Token> } and similar for Revoke) plus necessary imports
(anchor_lang, anchor_spl::token::{self, TokenAccount, Token, Approve, Revoke} or
renamed types) and a small doc/tests snippet; otherwise remove the placeholder
file until the implementation is ready.

In `@snippets/code-snippets/light-token/approve-revoke/program/native.mdx`:
- Around line 56-63: This file contains duplicated top-level imports and a `//
---` separator in a single code fence which will cause compilation errors;
remove the duplicate imports or split the examples into separate code fences so
each example has its own imports. Specifically, either delete the repeated `use`
lines referencing authority_seeds, RevokeCpi (light_token_sdk::token::RevokeCpi)
and the Solana types (AccountInfo, ProgramResult, ProgramError) so only one
import block remains, or place the second example (the `// ---` section) into
its own fenced block with its own imports to avoid duplicate symbols.

In `@snippets/code-snippets/light-token/burn/rust-client/full.mdx`:
- Around line 10-40: The test currently hardcodes initial_amount = 1_000_000u64
which couples it to shared::setup(); instead, read the pre-burn balance from the
ATA returned by rpc.get_account(ata) and deserialize it using
light_token_interface::state::Token::deserialize to set initial_amount
dynamically before constructing and sending the Burn instruction; then use that
initial_amount in the final assert_eq! check (token.amount == initial_amount -
burn_amount). Locate references to initial_amount, shared::setup(),
rpc.get_account(ata), and Token::deserialize to implement this change.

In
`@snippets/code-snippets/light-token/close-token-account/rust-client/basic.mdx`:
- Around line 1-11: Replace the incorrect type CloseTokenAccount with
CloseAccount in this snippet so it matches the full example and compiles;
specifically update the call site that constructs the instruction (use
CloseAccount::new with the same parameters LIGHT_TOKEN_PROGRAM_ID,
account.pubkey(), payer.pubkey(), owner and keep the trailing .instruction()?
invocation) to ensure the SDK type and API are consistent.

In `@snippets/code-snippets/light-token/create-mint/rust-client/basic.mdx`:
- Line 11: Replace the invalid Rust placeholder `...` inside the extension entry
so the snippet compiles and is clear: update the `extensions:
Some(vec![ExtensionInstructionData::TokenMetadata(...)]),` usage of
`ExtensionInstructionData::TokenMetadata` to either use a comment-style
placeholder (e.g., `/* fields here */`) or show a minimal concrete TokenMetadata
construction with required fields (for example supplying name, symbol, uri and
any required defaults) so readers can copy the example without syntax errors;
ensure you reference the `ExtensionInstructionData::TokenMetadata` variant and
the `extensions: Some(vec![...])` container in the replacement.

In `@snippets/code-snippets/light-token/freeze-thaw/program/anchor.mdx`:
- Around line 1-2: The file anchor.mdx currently contains an empty Rust code
block; either remove this placeholder file or populate it with a full Anchor
program implementation for the freeze/thaw feature. If adding implementation,
create an Anchor program module (e.g., program FreezeThaw) with two instruction
handlers (freeze and thaw), corresponding account structs (e.g., FreezeContext,
ThawContext) that require the token mint, token account, authority, and
system/token program references, and include appropriate access control checks
and CPI calls to the token program to set/clear the freeze authority; ensure the
module and function names (FreezeThaw, freeze, thaw, FreezeContext, ThawContext)
appear in the anchor.mdx example so reviewers can find and test the snippet.

In `@snippets/code-snippets/light-token/freeze-thaw/program/native.mdx`:
- Around line 44-51: The duplicate import block repeats symbols already imported
earlier and will cause Rust compile errors; remove the redundant use lines (the
second block that re-imports authority_seeds, ThawCpi, AccountInfo,
ProgramResult, ProgramError) and instead add ThawCpi to the original import line
where authority_seeds is first imported so the initial use statement includes
ThawCpi.

In `@snippets/code-snippets/light-token/mint-to/program/anchor.mdx`:
- Around line 40-41: Remove the unused light_token_program account field from
the accounts struct (the line declaring pub light_token_program:
AccountInfo<'info>) since mint_to does not use it nor pass it to MintToCpi;
delete the field and its CHECK comment, then search for any remaining references
to light_token_program (in the mint_to handler, CPI construction, tests or
comments) and remove or update them so the struct and CPI invocation only
include the accounts actually used.

In `@snippets/code-snippets/light-token/transfer-interface/program/anchor.mdx`:
- Around line 47-48: The TransferAccounts struct declares an unused account
field light_token_program; either remove this field from TransferAccounts if the
CPI does not require the light token program, or pass it into the CPI
initializer by adding the account to the TransferInterfaceCpi::new(...) call
(and any related context builders) so the CPI receives the light_token_program
account; update any usages of TransferAccounts or the CPI context accordingly to
keep field names consistent.

In `@snippets/compressible-rent-explained.mdx`:
- Line 11: Replace the incorrect "776 lamports" text with "766 lamports"
wherever the documentation sentence "When the account's rent is below 3h, the
transaction payer tops up 776 lamports." appears so it matches the
implementation value `write_top_up: 766`; update the other snippet mentioning
the top-up amount to use 766 as well to keep docs consistent with the code.

In `@snippets/jsx/code-compare.jsx`:
- Around line 18-23: The handleCopy function calls
navigator.clipboard.writeText(...) without handling rejections; wrap the
writeText call in a try/catch (or check navigator.clipboard and fallback) inside
handleCopy to catch errors, log or silently handle failures, and still setCopied
only on success (or ensure state reflects success/failure appropriately); refer
to handleCopy, showingFirst, firstCode, secondCode, and setCopied when
implementing the change.
🧹 Nitpick comments (11)
snippets/code-snippets/light-token/mint-to/rust-client/full.mdx (1)

37-39: Missing import for light_token_interface::state::Token.

The Token type is used with a fully qualified path on line 38, but other dependencies are imported at the top. For consistency with the import style used elsewhere in this snippet, consider adding the import.

Suggested fix
 use borsh::BorshDeserialize;
 use light_client::rpc::Rpc;
 use light_token_sdk::token::MintTo;
+use light_token_interface::state::Token;
 use shared::SetupContext;
 use solana_sdk::signer::Signer;

Then update line 38:

-    let token = light_token_interface::state::Token::deserialize(&mut &ata_data.data[..]).unwrap();
+    let token = Token::deserialize(&mut &ata_data.data[..]).unwrap();
scripts/copy-rust-snippets.sh (1)

26-33: Missing trailing newline handling.

If the source file doesn't end with a newline, the closing ``` will appear on the same line as the last code line, potentially causing rendering issues.

Proposed fix
 wrap_rust() {
     local input_file="$1"
     local output_file="$2"
     echo '```rust' > "$output_file"
     cat "$input_file" >> "$output_file"
+    # Ensure newline before closing fence
+    [[ -n "$(tail -c1 "$input_file")" ]] && echo "" >> "$output_file"
     echo '```' >> "$output_file"
     echo "Created: $output_file"
 }
scripts/copy-program-snippets.sh (2)

34-55: wrap_rust_multi creates empty code block when no files exist.

If none of the input files exist, the function still outputs an empty ```rust ``` block. Consider adding validation.

Proposed fix
 wrap_rust_multi() {
     local output_file="$1"
     shift
     local input_files=("$@")
+    
+    # Check if at least one file exists
+    local has_files=false
+    for input_file in "${input_files[@]}"; do
+        if [ -f "$input_file" ]; then
+            has_files=true
+            break
+        fi
+    done
+    
+    if [ "$has_files" = false ]; then
+        echo "  WARNING: No input files found for $output_file"
+        return 1
+    fi

     echo '```rust' > "$output_file"
     local first=true
     for input_file in "${input_files[@]}"; do

24-31: Consider extracting shared wrap_rust function.

This function is duplicated in copy-rust-snippets.sh. Consider extracting it into a shared script that both can source.

snippets/code-snippets/light-token/freeze-thaw/rust-client/freeze-full.mdx (1)

28-31: Consider adding an assertion to verify the freeze succeeded.

The test sends the freeze transaction but doesn't verify the account state changed. Adding an assertion would make this a more complete example for documentation purposes.

💡 Suggested addition
     rpc.create_and_send_transaction(&[freeze_ix], &payer.pubkey(), &[&payer])
         .await
         .unwrap();
+
+    // Verify account is frozen
+    let account_data = rpc.get_token_account(ata).await.unwrap();
+    assert!(account_data.is_frozen);
 }
light-token/cookbook/approve-revoke.mdx (1)

7-8: Stray horizontal rule may cause rendering issues.

The standalone --- on line 8 creates a horizontal rule immediately after the frontmatter. If this is intentional for visual separation, consider using an explicit <hr /> for clarity. If unintentional, remove it to avoid potential MDX parsing issues.

💡 Suggested fix (if unintentional)
 ---
 
----
-
 import TokenClientPrerequisites from "/snippets/light-token-guides/light-token-client-prerequisites.mdx";
snippets/code-snippets/light-token/mint-to/rust-client/basic.mdx (1)

1-12: Clarify the origin of params for copy‑paste friendliness.

A short inline hint (or a minimal placeholder initialization) would make the snippet self‑contained and reduce reader confusion.

✏️ Suggested tweak
 use light_token_sdk::token::MintTo;
 
+// params: MintTo params prepared earlier in the guide
 let instruction = MintTo::new(
     params,
     payer.pubkey(),
     state_tree,
     output_queue,
     input_queue,
     vec![recipient_account.pubkey()],
 )
 .instruction()?;
snippets/code-snippets/light-token/create-mint/rust-client/full.mdx (1)

35-62: Reuse the derived mint PDA tuple for clarity.

Avoid recomputing find_mint_address and keep the bump tied to the same tuple.

♻️ Proposed refactor
-    let compression_address =
-        derive_mint_compressed_address(&mint_seed.pubkey(), &address_tree.tree);
-    let mint = find_mint_address(&mint_seed.pubkey()).0; // on-chain Mint PDA
+    let compression_address =
+        derive_mint_compressed_address(&mint_seed.pubkey(), &address_tree.tree);
+    let (mint, mint_bump) = find_mint_address(&mint_seed.pubkey()); // on-chain Mint PDA
@@
-        bump: find_mint_address(&mint_seed.pubkey()).1,
+        bump: mint_bump,
light-token/cookbook/mint-to.mdx (1)

117-129: Minor: Missing import statement context in code block.

The invoke (External Signer) code block uses authority but doesn't show where it comes from, unlike the invoke_signed variant which shows authority_seeds!(bump). For documentation clarity, consider adding a brief comment or showing how authority is obtained from the accounts.

snippets/code-snippets/light-token/burn/program/native.mdx (1)

14-17: Inconsistent data validation approach compared to burn_invoke_signed.

burn_invoke uses data.try_into() which requires exactly 8 bytes, while burn_invoke_signed (line 34) uses data.len() < 9 which allows extra trailing bytes. For consistency with burn_invoke_signed and the transfer interface patterns in this PR, consider using explicit length validation:

♻️ Suggested refactor for consistency
-    let amount = u64::from_le_bytes(
-        data.try_into()
-            .map_err(|_| ProgramError::InvalidInstructionData)?,
-    );
+    if data.len() < 8 {
+        return Err(ProgramError::InvalidInstructionData);
+    }
+    let amount = u64::from_le_bytes(data[0..8].try_into().unwrap());
snippets/code-snippets/light-token/create-mint/program/anchor.mdx (1)

14-65: Avoid hard-coded defaults if SDK constants exist.

The rent_payment and write_top_up defaults (16/766) are easy to drift; consider referencing SDK constants or documenting the source of these values.

Comment on lines +20 to +22
1. Burn permanently destroys tokens by reducing the balance in a token account.
2. Burned tokens are removed from circulation and decreases the supply tracked on the mint account.
3. Only the token account owner (or approved delegate) can burn tokens.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix subject‑verb agreement in the burn description.

✏️ Proposed fix
-2. Burned tokens are removed from circulation and decreases the supply tracked on the mint account.
+2. Burned tokens are removed from circulation and decrease the supply tracked on the mint account.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
1. Burn permanently destroys tokens by reducing the balance in a token account.
2. Burned tokens are removed from circulation and decreases the supply tracked on the mint account.
3. Only the token account owner (or approved delegate) can burn tokens.
1. Burn permanently destroys tokens by reducing the balance in a token account.
2. Burned tokens are removed from circulation and decrease the supply tracked on the mint account.
3. Only the token account owner (or approved delegate) can burn tokens.
🤖 Prompt for AI Agents
In `@light-token/cookbook/burn.mdx` around lines 20 - 22, The second sentence has
a subject-verb agreement error: in the sentence starting with "Burned tokens are
removed from circulation and decreases the supply tracked on the mint account"
change the verb "decreases" to "decrease" so it agrees with the plural subject
"Burned tokens" (i.e., update the sentence that begins "Burned tokens are
removed from circulation..." to use "decrease the supply tracked on the mint
account").

Comment on lines +6 to +8
NATIVE_DIR="/home/tilo/Workspace/examples-light-token/program-examples/native/program/src/instructions"
ANCHOR_DIR="/home/tilo/Workspace/examples-light-token/program-examples/anchor/programs"
SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/light-token"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Hardcoded absolute paths will break portability.

Same issue as copy-rust-snippets.sh - these paths are specific to your local machine.

Proposed fix
-NATIVE_DIR="/home/tilo/Workspace/examples-light-token/program-examples/native/program/src/instructions"
-ANCHOR_DIR="/home/tilo/Workspace/examples-light-token/program-examples/anchor/programs"
-SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/light-token"
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+REPO_ROOT="$(dirname "$SCRIPT_DIR")"
+NATIVE_DIR="${NATIVE_DIR:-$REPO_ROOT/../examples-light-token/program-examples/native/program/src/instructions}"
+ANCHOR_DIR="${ANCHOR_DIR:-$REPO_ROOT/../examples-light-token/program-examples/anchor/programs}"
+SNIPPETS_DIR="${SNIPPETS_DIR:-$REPO_ROOT/snippets/code-snippets/light-token}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
NATIVE_DIR="/home/tilo/Workspace/examples-light-token/program-examples/native/program/src/instructions"
ANCHOR_DIR="/home/tilo/Workspace/examples-light-token/program-examples/anchor/programs"
SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/light-token"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
NATIVE_DIR="${NATIVE_DIR:-$REPO_ROOT/../examples-light-token/program-examples/native/program/src/instructions}"
ANCHOR_DIR="${ANCHOR_DIR:-$REPO_ROOT/../examples-light-token/program-examples/anchor/programs}"
SNIPPETS_DIR="${SNIPPETS_DIR:-$REPO_ROOT/snippets/code-snippets/light-token}"
🤖 Prompt for AI Agents
In `@scripts/copy-program-snippets.sh` around lines 6 - 8, The script uses
hardcoded absolute paths (NATIVE_DIR, ANCHOR_DIR, SNIPPETS_DIR) which breaks
portability; change them to computed relative paths by deriving a base directory
(e.g., using the script directory via BASH_SOURCE or the repository root via git
rev-parse --show-toplevel) and then build NATIVE_DIR, ANCHOR_DIR and
SNIPPETS_DIR from that base so the script works on other machines; update any
usages in copy-program-snippets.sh to reference the new variables.

Comment on lines +6 to +7
EXAMPLES_DIR="/home/tilo/Workspace/examples-light-token/rust-client/tests"
SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/light-token"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Hardcoded absolute paths will break portability.

These paths are specific to your local machine and will fail for other developers or CI environments. Consider using relative paths or environment variables.

Proposed fix using relative paths or environment variables
-EXAMPLES_DIR="/home/tilo/Workspace/examples-light-token/rust-client/tests"
-SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/light-token"
+# Use environment variables with fallback to relative paths
+EXAMPLES_DIR="${EXAMPLES_DIR:-../examples-light-token/rust-client/tests}"
+SNIPPETS_DIR="${SNIPPETS_DIR:-./snippets/code-snippets/light-token}"

Or use script-relative paths:

-EXAMPLES_DIR="/home/tilo/Workspace/examples-light-token/rust-client/tests"
-SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/light-token"
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+REPO_ROOT="$(dirname "$SCRIPT_DIR")"
+EXAMPLES_DIR="${EXAMPLES_DIR:-$REPO_ROOT/../examples-light-token/rust-client/tests}"
+SNIPPETS_DIR="${SNIPPETS_DIR:-$REPO_ROOT/snippets/code-snippets/light-token}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
EXAMPLES_DIR="/home/tilo/Workspace/examples-light-token/rust-client/tests"
SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/light-token"
# Use environment variables with fallback to relative paths
EXAMPLES_DIR="${EXAMPLES_DIR:-../examples-light-token/rust-client/tests}"
SNIPPETS_DIR="${SNIPPETS_DIR:-./snippets/code-snippets/light-token}"
🤖 Prompt for AI Agents
In `@scripts/copy-rust-snippets.sh` around lines 6 - 7, The script
copy-rust-snippets.sh uses hardcoded absolute paths in EXAMPLES_DIR and
SNIPPETS_DIR which break portability; change these to either respect environment
variables (e.g., read EXAMPLES_DIR and SNIPPETS_DIR from env with sensible
defaults) or compute them relative to the script location (use the script
dirname to build paths) so the variables EXAMPLES_DIR and SNIPPETS_DIR are not
machine-specific and will work in CI and other dev machines.

Comment on lines +132 to +146
"// light-token transfer",
"use light_token_sdk::token::TransferInterface;",
"",
"let ix = TransferInterface {",
" source,",
" destination,",
" amount,",
" decimals,",
" authority: payer.pubkey(),",
" payer: payer.pubkey(),",
" spl_interface: None,",
" max_top_up: None,",
" source_owner: LIGHT_TOKEN_PROGRAM_ID,",
" destination_owner: LIGHT_TOKEN_PROGRAM_ID,",
"}",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

git ls-files | grep -E "code-compare|snippets" | head -20

Repository: Lightprotocol/docs-v2

Length of output: 1102


🏁 Script executed:

fd "code-compare-snippets" --type f

Repository: Lightprotocol/docs-v2

Length of output: 159


🏁 Script executed:

wc -l "snippets/code-samples/code-compare-snippets.jsx" 2>/dev/null || echo "File not found"

Repository: Lightprotocol/docs-v2

Length of output: 116


🏁 Script executed:

sed -n '132,146p' snippets/code-samples/code-compare-snippets.jsx

Repository: Lightprotocol/docs-v2

Length of output: 491


🏁 Script executed:

sed -n '1,50p' snippets/code-samples/code-compare-snippets.jsx

Repository: Lightprotocol/docs-v2

Length of output: 1221


🏁 Script executed:

rg "LIGHT_TOKEN_PROGRAM_ID" snippets/code-samples/code-compare-snippets.jsx -B 2 -A 2

Repository: Lightprotocol/docs-v2

Length of output: 514


Add LIGHT_TOKEN_PROGRAM_ID to the import statement.

The code references LIGHT_TOKEN_PROGRAM_ID at lines 145-146 but doesn't import it. This pattern is already correctly implemented elsewhere in the file (e.g., in lightCloseAccountRustCode).

Suggested fix
-  "use light_token_sdk::token::TransferInterface;",
+  "use light_token_sdk::token::{TransferInterface, LIGHT_TOKEN_PROGRAM_ID};",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"// light-token transfer",
"use light_token_sdk::token::TransferInterface;",
"",
"let ix = TransferInterface {",
" source,",
" destination,",
" amount,",
" decimals,",
" authority: payer.pubkey(),",
" payer: payer.pubkey(),",
" spl_interface: None,",
" max_top_up: None,",
" source_owner: LIGHT_TOKEN_PROGRAM_ID,",
" destination_owner: LIGHT_TOKEN_PROGRAM_ID,",
"}",
"// light-token transfer",
"use light_token_sdk::token::{TransferInterface, LIGHT_TOKEN_PROGRAM_ID};",
"",
"let ix = TransferInterface {",
" source,",
" destination,",
" amount,",
" decimals,",
" authority: payer.pubkey(),",
" payer: payer.pubkey(),",
" spl_interface: None,",
" max_top_up: None,",
" source_owner: LIGHT_TOKEN_PROGRAM_ID,",
" destination_owner: LIGHT_TOKEN_PROGRAM_ID,",
"}",
🤖 Prompt for AI Agents
In `@snippets/code-samples/code-compare-snippets.jsx` around lines 132 - 146, The
snippet references LIGHT_TOKEN_PROGRAM_ID but only imports TransferInterface;
update the import to bring LIGHT_TOKEN_PROGRAM_ID into scope (e.g., add
LIGHT_TOKEN_PROGRAM_ID to the use statement that currently imports
TransferInterface) so the TransferInterface initialization can set source_owner
and destination_owner to LIGHT_TOKEN_PROGRAM_ID.

Comment on lines +1 to +2
```rust
```
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's verify the file exists and read its contents
cat snippets/code-snippets/light-token/approve-revoke/program/anchor.mdx

Repository: Lightprotocol/docs-v2

Length of output: 78


🏁 Script executed:

# Check if there are other anchor.mdx files and their contents
fd -e mdx 'anchor.mdx' snippets/code-snippets/light-token --exec bash -c 'echo "=== File: {} ===" && wc -l {} && head -30 {}' \;

Repository: Lightprotocol/docs-v2

Length of output: 7755


🏁 Script executed:

# Get a broader view of the directory structure
find snippets/code-snippets/light-token -name "*.mdx" -type f | head -20

Repository: Lightprotocol/docs-v2

Length of output: 1328


Add implementation or remove placeholder file for approve-revoke program.

The approve-revoke/program/anchor.mdx file contains only an empty Rust code block. All comparable Anchor program examples in the light-token snippets directory (create-ata, mint-to, burn, etc.) contain full implementations (40+ lines). Either add the actual Anchor program code for approve-revoke functionality, or remove this placeholder file until content is ready.

🤖 Prompt for AI Agents
In `@snippets/code-snippets/light-token/approve-revoke/program/anchor.mdx` around
lines 1 - 2, The file is a placeholder empty Rust block for the approve-revoke
Anchor program; either replace it with a full Anchor program implementing
approve/revoke handlers or delete the file. To implement, add an Anchor program
module (e.g., #[program] pub mod approve_revoke) with two exported functions pub
fn approve(ctx: Context<Approve>, amount: u64) and pub fn revoke(ctx:
Context<Revoke>) that call the CPI helpers in anchor_spl::token::approve and
anchor_spl::token::revoke, and add corresponding context structs (struct
Approve<'info> { #[account(mut)] source: Account<'info, TokenAccount>,
#[account(signer)] authority: AccountInfo<'info>, token_program: Program<'info,
Token> } and similar for Revoke) plus necessary imports (anchor_lang,
anchor_spl::token::{self, TokenAccount, Token, Approve, Revoke} or renamed
types) and a small doc/tests snippet; otherwise remove the placeholder file
until the implementation is ready.

Comment on lines +44 to +51
// ---

use super::authority_seeds;
use light_token_sdk::token::ThawCpi;
use solana_program::{
account_info::AccountInfo, entrypoint::ProgramResult,
program_error::ProgramError,
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Duplicate imports will cause compilation errors.

Lines 46-51 duplicate the imports already declared at lines 2-7. This would fail to compile in actual Rust code. Since this is documentation, the code should remain syntactically valid.

🔧 Suggested fix: Remove duplicate imports
-// ---
-
-use super::authority_seeds;
-use light_token_sdk::token::ThawCpi;
-use solana_program::{
-    account_info::AccountInfo, entrypoint::ProgramResult,
-    program_error::ProgramError,
-};
+// --- Thaw Operations ---

And add ThawCpi to the original import:

-use light_token_sdk::token::FreezeCpi;
+use light_token_sdk::token::{FreezeCpi, ThawCpi};
🤖 Prompt for AI Agents
In `@snippets/code-snippets/light-token/freeze-thaw/program/native.mdx` around
lines 44 - 51, The duplicate import block repeats symbols already imported
earlier and will cause Rust compile errors; remove the redundant use lines (the
second block that re-imports authority_seeds, ThawCpi, AccountInfo,
ProgramResult, ProgramError) and instead add ThawCpi to the original import line
where authority_seeds is first imported so the initial use statement includes
ThawCpi.

Comment on lines +40 to +41
/// CHECK: Light token program for CPI
pub light_token_program: AccountInfo<'info>,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n snippets/code-snippets/light-token/mint-to/program/anchor.mdx

Repository: Lightprotocol/docs-v2

Length of output: 1561


🏁 Script executed:

rg -n "MintToCpi" --type-add 'mdx:*.mdx' --type mdx -A 10

Repository: Lightprotocol/docs-v2

Length of output: 6793


Remove unused light_token_program account from the accounts struct.

The light_token_program field is declared at line 41 but is never used in the mint_to function. It is not passed to MintToCpi and serves no purpose in the CPI invocation. Remove it to avoid confusion.

🤖 Prompt for AI Agents
In `@snippets/code-snippets/light-token/mint-to/program/anchor.mdx` around lines
40 - 41, Remove the unused light_token_program account field from the accounts
struct (the line declaring pub light_token_program: AccountInfo<'info>) since
mint_to does not use it nor pass it to MintToCpi; delete the field and its CHECK
comment, then search for any remaining references to light_token_program (in the
mint_to handler, CPI construction, tests or comments) and remove or update them
so the struct and CPI invocation only include the accounts actually used.

Comment on lines +47 to +48
/// CHECK: Light token program for CPI
pub light_token_program: AccountInfo<'info>,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's locate the file and understand the repository structure
find . -name "anchor.mdx" -path "*/light-token/transfer-interface/program/*" 2>/dev/null | head -5

Repository: Lightprotocol/docs-v2

Length of output: 139


🏁 Script executed:

#!/bin/bash
# Search for TransferInterfaceCpi::new usage
rg -n "TransferInterfaceCpi::new" -A 10 -B 2

Repository: Lightprotocol/docs-v2

Length of output: 5911


🏁 Script executed:

#!/bin/bash
# Also search for TransferAccounts struct definition to see the full context
rg -n "struct TransferAccounts" -A 20

Repository: Lightprotocol/docs-v2

Length of output: 1917


🏁 Script executed:

#!/bin/bash
# Check for any usage of light_token_program in the codebase
rg -n "light_token_program" -B 2 -A 2

Repository: Lightprotocol/docs-v2

Length of output: 2900


🏁 Script executed:

#!/bin/bash
# View the complete anchor.mdx file to see full context
cat -n snippets/code-snippets/light-token/transfer-interface/program/anchor.mdx

Repository: Lightprotocol/docs-v2

Length of output: 1869


Remove unused light_token_program account from TransferAccounts struct or pass it to the CPI call.

The light_token_program account is declared at lines 47-48 but is not passed to TransferInterfaceCpi::new() on line 18. Either remove it from the struct if the CPI doesn't require it, or add it to the CPI call if it's needed for the operation.

🤖 Prompt for AI Agents
In `@snippets/code-snippets/light-token/transfer-interface/program/anchor.mdx`
around lines 47 - 48, The TransferAccounts struct declares an unused account
field light_token_program; either remove this field from TransferAccounts if the
CPI does not require the light token program, or pass it into the CPI
initializer by adding the account to the TransferInterfaceCpi::new(...) call
(and any related context builders) so the CPI receives the light_token_program
account; update any usages of TransferAccounts or the CPI context accordingly to
keep field names consistent.


* At account creation ~17,208 lamports <Tooltip tip="24 h = 16 epochs, where 1 rent-epoch ≈ 1.5h ≈ 13,500 slots at 400ms per slot">for 24h of rent</Tooltip> <br/>
and <Tooltip tip="Covers transaction cost to compress accounts (10,000) and protocol incentive (1,000). Transaction cost might vary.">compression incentive</Tooltip>.
* When the account's rent is below 3h, the transaction payer tops up 776 lamports.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for both lamport values in mdx files
echo "=== Searching for 776 lamports ==="
rg -n '776' -g '*.mdx' 

echo -e "\n=== Searching for 766 lamports ==="
rg -n '766' -g '*.mdx'

echo -e "\n=== Searching for write_top_up ==="
rg -n 'write_top_up' -g '*.mdx' -A 2

Repository: Lightprotocol/docs-v2

Length of output: 3637


🏁 Script executed:

echo "=== Context from compressible-rent-explained.mdx around line 11 ==="
sed -n '1,15p' snippets/compressible-rent-explained.mdx

echo -e "\n=== Context from compressible-default-rent-config.mdx ==="
cat snippets/compressible-default-rent-config.mdx

echo -e "\n=== Context from basic.mdx around line 13 ==="
sed -n '10,20p' snippets/code-snippets/light-token/create-mint/rust-client/basic.mdx

Repository: Lightprotocol/docs-v2

Length of output: 2002


Update documentation to match code: change 776 to 766 lamports.

Documentation files state the top-up as "776 lamports", but all code snippets consistently use write_top_up: 766. Update snippets/compressible-rent-explained.mdx line 11 and snippets/compressible-default-rent-config.mdx line 3 to match the actual implementation value of 766 lamports.

🤖 Prompt for AI Agents
In `@snippets/compressible-rent-explained.mdx` at line 11, Replace the incorrect
"776 lamports" text with "766 lamports" wherever the documentation sentence
"When the account's rent is below 3h, the transaction payer tops up 776
lamports." appears so it matches the implementation value `write_top_up: 766`;
update the other snippet mentioning the top-up amount to use 766 as well to keep
docs consistent with the code.

Comment on lines +18 to +23
const handleCopy = async () => {
const codeToCopy = showingFirst ? firstCode : secondCode;
await navigator.clipboard.writeText(codeToCopy);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists and read the relevant lines
if [ -f "snippets/jsx/code-compare.jsx" ]; then
  echo "=== File exists, showing lines 18-23 ==="
  sed -n '18,23p' snippets/jsx/code-compare.jsx
  echo ""
  echo "=== Showing broader context (lines 1-30) ==="
  head -30 snippets/jsx/code-compare.jsx
else
  echo "File not found at snippets/jsx/code-compare.jsx"
fi

Repository: Lightprotocol/docs-v2

Length of output: 1396


🏁 Script executed:

# Search for other clipboard usages in the codebase
echo "=== Searching for clipboard usage ==="
rg "clipboard" --type jsx --type js -i -n

Repository: Lightprotocol/docs-v2

Length of output: 147


🏁 Script executed:

# Check if there are any error handling patterns for async operations in the file
echo "=== Checking for try/catch patterns in the codebase ==="
rg "try\s*\{|catch\s*\(" --type jsx --type js -c | head -20

Repository: Lightprotocol/docs-v2

Length of output: 165


🏁 Script executed:

# Search for clipboard usage without type specification
echo "=== Searching for clipboard usage ==="
rg "clipboard" -n -A 3 -B 1

Repository: Lightprotocol/docs-v2

Length of output: 1116


🌐 Web query:

navigator.clipboard.writeText() error handling promise rejection unhandled failures

💡 Result:

Short answer

  • navigator.clipboard.writeText(text) returns a Promise that resolves on success and rejects on failure — you must catch/reject it (try/catch or .catch) to avoid unhandled rejections. [1][2]

Why it rejects (common reasons)

  • Not in a secure context (must be HTTPS). [2]
  • No transient user activation or missing clipboard-write permission (browsers differ: Chromium may require permission or user activation; Firefox/Safari require a user gesture). [2][3]
  • User denied permission or browser blocked the operation (NotAllowedError / SecurityError). [1][2]
  • Platform/OS clipboard failure or other I/O error (NotFoundError / generic DOMException). [1]

Best practices (minimal)

  1. Always await/handle the promise:
    async function copy(text) {
    try {
    await navigator.clipboard.writeText(text);
    // success
    } catch (err) {
    // handle failure / fallback
    }
    }
    .catch(...) if using promises. [1]

  2. Optionally check permission or user activation first:
    const p = await navigator.permissions?.query?.({ name: 'clipboard-write' });
    if (p && p.state === 'denied') { /* skip or fallback */ }
    // still use try/catch when writing. [3]

  3. Provide a fallback for older/blocked contexts:

    • Use a hidden textarea, select, document.execCommand('copy') as a fallback only after writeText fails. (execCommand is deprecated but still useful as fallback). Always catch writeText rejection before falling back. [1][2]
  4. Avoid unhandled rejections globally:
    window.addEventListener('unhandledrejection', e => {
    // log or handle e.reason
    });

Minimal example with fallback
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
return true;
} catch (err) {
// fallback: create textarea/select + document.execCommand('copy')
const ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed'; ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.select();
try {
document.execCommand('copy');
return true;
} catch (e) {
return false;
} finally {
document.body.removeChild(ta);
}
}
}

References

  • MDN Clipboard API (overview + write/writeText behavior, promise rejection). [1][2]
  • MDN Permissions API (clipboard-write permission explanation / browser differences). [3]

If you want, I can produce a complete copy-to-clipboard utility that includes permission checks, user-gesture detection, detailed error-handling, and telemetry/logging.


Guard clipboard writes to avoid unhandled promise rejections.

The navigator.clipboard.writeText() API returns a Promise that can reject due to missing HTTPS context, denied permissions, or platform failures. Without error handling, these rejections remain unhandled. Add a try/catch block to gracefully handle failures:

🛠️ Proposed fix
  const handleCopy = async () => {
    const codeToCopy = showingFirst ? firstCode : secondCode;
+   try {
+     if (!navigator?.clipboard?.writeText) return;
+     await navigator.clipboard.writeText(codeToCopy);
+     setCopied(true);
+     setTimeout(() => setCopied(false), 2000);
+   } catch {
+     // Optional: surface a non-blocking UI hint or log
+   }
  };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleCopy = async () => {
const codeToCopy = showingFirst ? firstCode : secondCode;
await navigator.clipboard.writeText(codeToCopy);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
const handleCopy = async () => {
const codeToCopy = showingFirst ? firstCode : secondCode;
try {
if (!navigator?.clipboard?.writeText) return;
await navigator.clipboard.writeText(codeToCopy);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
// Optional: surface a non-blocking UI hint or log
}
};
🤖 Prompt for AI Agents
In `@snippets/jsx/code-compare.jsx` around lines 18 - 23, The handleCopy function
calls navigator.clipboard.writeText(...) without handling rejections; wrap the
writeText call in a try/catch (or check navigator.clipboard and fallback) inside
handleCopy to catch errors, log or silently handle failures, and still setCopied
only on success (or ensure state reflects success/failure appropriately); refer
to handleCopy, showingFirst, firstCode, secondCode, and setCopied when
implementing the change.

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.

2 participants