diff --git a/light-token/toolkits/for-streaming-tokens.mdx b/light-token/toolkits/for-streaming-tokens.mdx
index 8b181e66..1bc431d7 100644
--- a/light-token/toolkits/for-streaming-tokens.mdx
+++ b/light-token/toolkits/for-streaming-tokens.mdx
@@ -5,153 +5,45 @@ description: "Light token accounts follow the same layout as SPL-token accounts,
keywords: ["streaming tokens for solana apps", "scalable token distribution on solana", "token streaming for developers"]
---
-import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx";
+import WarmUpAction from "/snippets/code-snippets/light-token/warm-up/warm-up-action.mdx";
+import WarmUpInstruction from "/snippets/code-snippets/light-token/warm-up/warm-up-instruction.mdx";
-When a market becomes inactive, its token accounts and related PDAs will be compressed - their state is committed and effectively frozen until a client decompresses it.
+When a market becomes inactive, its token accounts and related PDAs will
+be compressed automatically (cold storage).
+The state is cryptographically preserved on the Solana ledger.
While compressed, pure on-chain lookups will return uninitialized.
-Your indexer should keep tracking, quoting, and routing markets even if the on-chain account shows `is_initialized: false`, `is_compressed: true`. To trade a cold market, the first client must prepend an idempotent decompress "warm up" instruction.
+Your indexer should keep tracking, quoting, and routing markets even if the
+on-chain account shows `is_initialized: false`, `is_compressed: true`.
+To trade a cold market, the first client must prepend an
+idempotent decompress "warm up" instruction.
Find the source code
- [here](https://github.com/Lightprotocol/light-protocol/blob/main/js/compressed-token/tests/e2e/load-ata-standard.test.ts).
+ [here](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/indexing-tokens).
-## Setup
-
-
-
-### Load Compressed Tokens to Hot Balance
-
-
-```typescript Action
-import { Keypair } from "@solana/web3.js";
-import { createRpc, bn } from "@lightprotocol/stateless.js";
-import {
- createMint,
- mintTo,
- loadAta,
- getAssociatedTokenAddressInterface,
-} from "@lightprotocol/compressed-token";
-
-async function main() {
- const rpc = createRpc();
- const payer = Keypair.generate();
- await rpc.requestAirdrop(payer.publicKey, 10e9);
-
- const owner = Keypair.generate();
- await rpc.requestAirdrop(owner.publicKey, 1e9);
-
- const mintAuthority = Keypair.generate();
- const mintKeypair = Keypair.generate();
- const { mint } = await createMint(
- rpc,
- payer,
- mintAuthority.publicKey,
- 9,
- mintKeypair,
- );
-
- await mintTo(rpc, payer, mint, owner.publicKey, mintAuthority, bn(1000));
-
- // Get light-token ATA address
- const tokenAta = getAssociatedTokenAddressInterface(mint, owner.publicKey);
-
- // Load compressed tokens to hot balance
- // Creates ATA if needed, returns null if nothing to load
- const signature = await loadAta(rpc, tokenAta, owner, mint, payer);
-
- if (signature) {
- console.log("Loaded tokens to hot balance");
- console.log("Transaction:", signature);
- } else {
- console.log("Nothing to load");
- }
-}
-
-main().catch(console.error);
-```
-
-```typescript Instruction
-import { Keypair, ComputeBudgetProgram } from "@solana/web3.js";
-import {
- createRpc,
- bn,
- buildAndSignTx,
- sendAndConfirmTx,
- dedupeSigner,
-} from "@lightprotocol/stateless.js";
-import {
- createMint,
- mintTo,
- createLoadAtaInstructions,
- getAssociatedTokenAddressInterface,
-} from "@lightprotocol/compressed-token";
-
-async function main() {
- const rpc = createRpc();
- const payer = Keypair.generate();
- await rpc.requestAirdrop(payer.publicKey, 10e9);
-
- const owner = Keypair.generate();
- await rpc.requestAirdrop(owner.publicKey, 1e9);
-
- const mintAuthority = Keypair.generate();
- const mintKeypair = Keypair.generate();
- const { mint } = await createMint(
- rpc,
- payer,
- mintAuthority.publicKey,
- 9,
- mintKeypair
- );
-
- await mintTo(rpc, payer, mint, owner.publicKey, mintAuthority, bn(1000));
-
- // Get light-token ATA address
- const tokenAta = getAssociatedTokenAddressInterface(mint, owner.publicKey);
-
- // Create load instructions
- const ixs = await createLoadAtaInstructions(
- rpc,
- tokenAta,
- owner.publicKey,
- mint,
- payer.publicKey
- );
-
- if (ixs.length === 0) {
- console.log("Nothing to load");
- return;
- }
-
- // Build, sign, and send transaction
- const { blockhash } = await rpc.getLatestBlockhash();
- const additionalSigners = dedupeSigner(payer, [owner]);
-
- const tx = buildAndSignTx(
- [ComputeBudgetProgram.setComputeUnitLimit({ units: 500_000 }), ...ixs],
- payer,
- blockhash,
- additionalSigners
- );
-
- const signature = await sendAndConfirmTx(rpc, tx);
- console.log("Loaded tokens to hot balance");
- console.log("Transaction:", signature);
-}
+### Warm up a cold market and trade
-main().catch(console.error);
-```
+Prepend idempotent decompress instructions before your trade.
+`loadAta` returns null and `createLoadAtaInstructions` returns an empty array
+when the account is already hot, so this pattern is safe to use unconditionally.
-
+
+
+
+
+
+
+
+
-# Stream Light-Mint Accounts
+# Stream light-mint accounts
+/>
\ No newline at end of file
diff --git a/scripts/copy-light-token-snippets.sh b/scripts/copy-light-token-snippets.sh
index 862a7069..ec99f36c 100755
--- a/scripts/copy-light-token-snippets.sh
+++ b/scripts/copy-light-token-snippets.sh
@@ -13,6 +13,7 @@ RECIPES=("create-mint" "create-ata" "mint-to" "transfer-interface" "load-ata" "w
wrap_typescript() {
local input_file="$1"
local output_file="$2"
+ mkdir -p "$(dirname "$output_file")"
echo '```typescript' > "$output_file"
cat "$input_file" >> "$output_file"
echo '```' >> "$output_file"
@@ -40,6 +41,19 @@ for recipe in "${RECIPES[@]}"; do
fi
done
+# Indexing toolkit snippets
+INDEXING_DIR="/home/tilo/Workspace/examples-light-token/toolkits/indexing-tokens"
+echo "Processing: indexing-tokens toolkit"
+
+for variant in "warm-up-action" "warm-up-instruction"; do
+ src="$INDEXING_DIR/$variant.ts"
+ if [ -f "$src" ]; then
+ wrap_typescript "$src" "$SNIPPETS_DIR/warm-up/$variant.mdx"
+ else
+ echo " WARNING: Not found - $src"
+ fi
+done
+
echo ""
echo "Done! Created snippets in: $SNIPPETS_DIR"
echo ""
diff --git a/snippets/code-snippets/light-token/warm-up/warm-up-action.mdx b/snippets/code-snippets/light-token/warm-up/warm-up-action.mdx
new file mode 100644
index 00000000..0af83305
--- /dev/null
+++ b/snippets/code-snippets/light-token/warm-up/warm-up-action.mdx
@@ -0,0 +1,57 @@
+```typescript
+import "dotenv/config";
+import { Keypair } from "@solana/web3.js";
+import { createRpc } from "@lightprotocol/stateless.js";
+import {
+ createMintInterface,
+ createAtaInterface,
+ mintToCompressed,
+ loadAta,
+ transferInterface,
+ getAssociatedTokenAddressInterface,
+} from "@lightprotocol/compressed-token";
+import { homedir } from "os";
+import { readFileSync } from "fs";
+
+// devnet:
+// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`;
+// const rpc = createRpc(RPC_URL);
+// localnet:
+const rpc = createRpc();
+
+const payer = Keypair.fromSecretKey(
+ new Uint8Array(
+ JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")),
+ ),
+);
+
+(async function () {
+ // Inactive Light Tokens are cryptographically preserved on the Solana ledger
+ // as compressed tokens (cold storage)
+ // Setup: Get compressed tokens in light-token associated token account
+ const { mint } = await createMintInterface(rpc, payer, payer, null, 9);
+ await mintToCompressed(rpc, payer, mint, payer, [{ recipient: payer.publicKey, amount: 1000n }]);
+
+ const recipient = Keypair.generate();
+ await createAtaInterface(rpc, payer, mint, recipient.publicKey);
+
+ const senderAta = getAssociatedTokenAddressInterface(mint, payer.publicKey);
+ const recipientAta = getAssociatedTokenAddressInterface(mint, recipient.publicKey);
+
+ // Warm up: load compressed tokens to associated token account
+ // Returns null if already hot
+ await loadAta(rpc, senderAta, payer, mint, payer);
+
+ // Transfer tokens from hot balance
+ const tx = await transferInterface(
+ rpc,
+ payer,
+ senderAta,
+ mint,
+ recipientAta,
+ payer,
+ 500n,
+ );
+
+ console.log("Tx:", tx);
+})();```
diff --git a/snippets/code-snippets/light-token/warm-up/warm-up-instruction.mdx b/snippets/code-snippets/light-token/warm-up/warm-up-instruction.mdx
new file mode 100644
index 00000000..1ddee2f3
--- /dev/null
+++ b/snippets/code-snippets/light-token/warm-up/warm-up-instruction.mdx
@@ -0,0 +1,77 @@
+```typescript
+import "dotenv/config";
+import { Keypair } from "@solana/web3.js";
+import {
+ createRpc,
+ buildAndSignTx,
+ sendAndConfirmTx,
+} from "@lightprotocol/stateless.js";
+import {
+ createMintInterface,
+ createAtaInterface,
+ mintToCompressed,
+ createLoadAtaInstructions,
+ createTransferInterfaceInstruction,
+ getAssociatedTokenAddressInterface,
+} from "@lightprotocol/compressed-token";
+import { homedir } from "os";
+import { readFileSync } from "fs";
+
+// devnet:
+// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`;
+// const rpc = createRpc(RPC_URL);
+// localnet:
+const rpc = createRpc();
+
+const payer = Keypair.fromSecretKey(
+ new Uint8Array(
+ JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")),
+ ),
+);
+
+(async function () {
+ // Inactive Light Tokens are cryptographically preserved on the Solana ledger
+ // as compressed tokens (cold storage)
+ // Setup: Get compressed tokens in light-token associated token account
+ const { mint } = await createMintInterface(rpc, payer, payer, null, 9);
+ await mintToCompressed(rpc, payer, mint, payer, [{ recipient: payer.publicKey, amount: 1000n }]);
+
+ const recipient = Keypair.generate();
+ await createAtaInterface(rpc, payer, mint, recipient.publicKey);
+
+ const senderAta = getAssociatedTokenAddressInterface(mint, payer.publicKey);
+ const recipientAta = getAssociatedTokenAddressInterface(
+ mint,
+ recipient.publicKey,
+ );
+
+ // Warm up: load compressed tokens (cold) to sender's hot balance
+ // Returns [] if already hot — safe to call unconditionally
+ const loadIxs = await createLoadAtaInstructions(
+ rpc,
+ senderAta,
+ payer.publicKey,
+ mint,
+ payer.publicKey,
+ );
+
+ if (loadIxs.length > 0) {
+ const blockhash = await rpc.getLatestBlockhash();
+ const loadTx = buildAndSignTx(loadIxs, payer, blockhash.blockhash);
+ await sendAndConfirmTx(rpc, loadTx);
+ }
+
+ // Trade: transfer from hot balance
+ const transferIx = createTransferInterfaceInstruction(
+ senderAta,
+ recipientAta,
+ payer.publicKey,
+ 500n,
+ );
+
+ const blockhash = await rpc.getLatestBlockhash();
+ const tradeTx = buildAndSignTx([transferIx], payer, blockhash.blockhash);
+ const signature = await sendAndConfirmTx(rpc, tradeTx);
+
+ console.log("Tx:", signature);
+})();```