From f5d9b77d7326decfc8557b2b913d934c85740236 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Wed, 18 Mar 2026 00:45:58 +0000 Subject: [PATCH 01/19] Add payment docs: send, accept, advanced, interop, production readiness 10 new pages mirroring Solana payments structure: - Send: basic payment, memo, verify address, batch, fee abstraction - Accept: receive payments, verify payments - Advanced: spend permissions, deferred execution - Interop: wrap/unwrap for CEX on/off-ramp - Production readiness checklist Update docs.json navigation and overview.mdx cards. --- docs.json | 28 ++- .../accept-payments/receive-payments.mdx | 135 ++++++++++++ .../accept-payments/verify-payments.mdx | 90 ++++++++ .../payments/advanced/deferred-execution.mdx | 80 +++++++ .../payments/advanced/spend-permissions.mdx | 120 +++++++++++ light-token/payments/interop/wrap-unwrap.mdx | 167 +++++++++++++++ light-token/payments/overview.mdx | 17 ++ light-token/payments/production-readiness.mdx | 116 +++++++++++ .../payments/send-payments/basic-payment.mdx | 196 ++++++++++++++++++ .../payments/send-payments/batch-payments.mdx | 179 ++++++++++++++++ .../send-payments/fee-abstraction.mdx | 95 +++++++++ .../send-payments/payment-with-memo.mdx | 109 ++++++++++ .../payments/send-payments/verify-address.mdx | 80 +++++++ 13 files changed, 1411 insertions(+), 1 deletion(-) create mode 100644 light-token/payments/accept-payments/receive-payments.mdx create mode 100644 light-token/payments/accept-payments/verify-payments.mdx create mode 100644 light-token/payments/advanced/deferred-execution.mdx create mode 100644 light-token/payments/advanced/spend-permissions.mdx create mode 100644 light-token/payments/interop/wrap-unwrap.mdx create mode 100644 light-token/payments/production-readiness.mdx create mode 100644 light-token/payments/send-payments/basic-payment.mdx create mode 100644 light-token/payments/send-payments/batch-payments.mdx create mode 100644 light-token/payments/send-payments/fee-abstraction.mdx create mode 100644 light-token/payments/send-payments/payment-with-memo.mdx create mode 100644 light-token/payments/send-payments/verify-address.mdx diff --git a/docs.json b/docs.json index 4558a8e..bee9c97 100644 --- a/docs.json +++ b/docs.json @@ -57,7 +57,33 @@ "group": "For Stablecoin Payments", "pages": [ "light-token/payments/overview", - "light-token/payments/integration-guide" + "light-token/payments/integration-guide", + { + "group": "Send Payments", + "pages": [ + "light-token/payments/send-payments/basic-payment", + "light-token/payments/send-payments/payment-with-memo", + "light-token/payments/send-payments/verify-address", + "light-token/payments/send-payments/batch-payments", + "light-token/payments/send-payments/fee-abstraction" + ] + }, + { + "group": "Accept Payments", + "pages": [ + "light-token/payments/accept-payments/receive-payments", + "light-token/payments/accept-payments/verify-payments" + ] + }, + { + "group": "Advanced", + "pages": [ + "light-token/payments/advanced/spend-permissions", + "light-token/payments/advanced/deferred-execution" + ] + }, + "light-token/payments/interop/wrap-unwrap", + "light-token/payments/production-readiness" ] }, { diff --git a/light-token/payments/accept-payments/receive-payments.mdx b/light-token/payments/accept-payments/receive-payments.mdx new file mode 100644 index 0000000..e55a36d --- /dev/null +++ b/light-token/payments/accept-payments/receive-payments.mdx @@ -0,0 +1,135 @@ +--- +title: "Receive Payments" +sidebarTitle: "Receive payments" +description: "Prepare to receive token payments by loading cold accounts and sharing your associated token account address." +keywords: ["receive stablecoin solana", "light token receive", "load ata solana", "cold account loading"] +--- + +import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +Load creates the associated token account if needed and loads any cold balance into it. +Share the associated token account address with the sender. + + +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/receive.ts). + + + +**About loading**: Light Token accounts reduce account rent ~200x by auto-compressing inactive +accounts. Before any action, the SDK detects cold balances and adds +instructions to load them. This almost always fits in a single +atomic transaction with your regular transfer. APIs return `TransactionInstruction[][]` so the same +loop handles the rare multi-transaction case automatically. + + +## Setup + + + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; + +const rpc = createRpc(RPC_ENDPOINT); +``` + +## Derive the associated token account address + +Share this address with the sender so they know where to send tokens. + +```typescript +import { getAssociatedTokenAddressInterface } from "@lightprotocol/compressed-token/unified"; + +const ata = getAssociatedTokenAddressInterface(mint, recipient); +``` + +## Load the associated token account + + + + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { + createLoadAtaInstructions, + getAssociatedTokenAddressInterface, +} from "@lightprotocol/compressed-token/unified"; + +const ata = getAssociatedTokenAddressInterface(mint, recipient); + +// Returns TransactionInstruction[][]. +// Each inner array is one transaction. +// Almost always returns just one. +const instructions = await createLoadAtaInstructions( + rpc, + ata, + recipient, + mint, + payer.publicKey +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer]); +} +``` + + + + +```typescript +import { + loadAta, + getAssociatedTokenAddressInterface, +} from "@lightprotocol/compressed-token/unified"; + +const ata = getAssociatedTokenAddressInterface(mint, recipient); + +const sig = await loadAta(rpc, ata, recipient, mint, payer); +if (sig) console.log("Loaded:", sig); +``` + + + + + +The `payer` on load instructions is the fee sponsor. Set your application as the payer so users never interact with SOL. +See [fee abstraction](/light-token/payments/send-payments/fee-abstraction) for details. + + + + +```typescript +import { + createAssociatedTokenAccountInstruction, + getAssociatedTokenAddressSync, + getOrCreateAssociatedTokenAccount, +} from "@solana/spl-token"; + +const ata = getAssociatedTokenAddressSync(mint, recipient); + +// Instruction: +const tx = new Transaction().add( + createAssociatedTokenAccountInstruction(payer.publicKey, ata, recipient, mint) +); + +// Action: +const ata = await getOrCreateAssociatedTokenAccount( + connection, payer, mint, recipient +); +``` + + + +## Related guides + + + + Check balances and transaction history. + + + Sponsor rent top-ups so users never pay SOL. + + + + diff --git a/light-token/payments/accept-payments/verify-payments.mdx b/light-token/payments/accept-payments/verify-payments.mdx new file mode 100644 index 0000000..95781d3 --- /dev/null +++ b/light-token/payments/accept-payments/verify-payments.mdx @@ -0,0 +1,90 @@ +--- +title: "Verify Payments" +sidebarTitle: "Verify payments" +description: "Query token balances and transaction history to verify incoming payments." +keywords: ["verify payment solana", "token balance solana", "transaction history light token", "payment verification"] +--- + +import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +Query balances and transaction history to confirm incoming payments. + +## Setup + + + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; + +const rpc = createRpc(RPC_ENDPOINT); +``` + +## Query balance + + +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/get-balance.ts). + + +```typescript +import { + getAssociatedTokenAddressInterface, + getAtaInterface, +} from "@lightprotocol/compressed-token/unified"; + +const ata = getAssociatedTokenAddressInterface(mint, owner); +const account = await getAtaInterface(rpc, ata, owner, mint); + +console.log(account.parsed.amount); +``` + + + +```typescript +import { getAccount } from "@solana/spl-token"; + +const account = await getAccount(connection, ata); + +console.log(account.amount); +``` + + + +## Transaction history + + +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/get-history.ts). + + +Query all transactions for an owner across both on-chain and compressed state: + +```typescript +const result = await rpc.getSignaturesForOwnerInterface(owner); + +console.log(result.signatures); // Merged + deduplicated +console.log(result.solana); // On-chain transactions only +console.log(result.compressed); // Compressed transactions only +``` + +Use `getSignaturesForAddressInterface(address)` if you want address-specific rather than owner-wide history. + + + +```typescript +const signatures = await connection.getSignaturesForAddress(ata); +``` + + + +## Related guides + + + + Load cold accounts and prepare to receive. + + + Send a single token transfer. + + + + diff --git a/light-token/payments/advanced/deferred-execution.mdx b/light-token/payments/advanced/deferred-execution.mdx new file mode 100644 index 0000000..4caa11c --- /dev/null +++ b/light-token/payments/advanced/deferred-execution.mdx @@ -0,0 +1,80 @@ +--- +title: "Deferred Execution" +sidebarTitle: "Deferred execution" +description: "Sign transactions now and execute later using durable nonces, with considerations for Light Token's cold account lifecycle." +keywords: ["deferred execution solana", "durable nonce solana", "sign now execute later", "treasury operations solana"] +--- + +import SupportFooter from "/snippets/support-footer.mdx"; + +Durable nonces let you sign a transaction now and execute it later. +This is useful for treasury operations, multi-party approval workflows, +and scheduled payments. + +## How durable nonces work + +Standard Solana transactions expire after ~90 seconds (the blockhash lifetime). +Durable nonces replace the blockhash with a nonce value that does not expire, +allowing the signed transaction to be stored and submitted at any future time. + +For the complete durable nonce pattern, see +[Solana's deferred execution guide](https://solana.com/docs/payments/advanced-payments/deferred-execution). + +## Cold account considerations + + +Light Token accounts can transition between hot and cold states. This adds a constraint +to deferred execution that does not exist with standard SPL tokens. + + +When you build a deferred transaction, the SDK may include load instructions for cold accounts. +If the account's state changes between signing and execution, those instructions may become stale: + +- **Hot → cold**: The account compressed after signing. The pre-signed transfer instruction + expects a hot account but finds nothing on-chain. +- **Cold → hot**: Another transaction loaded the account after signing. The pre-signed load + instructions try to load an already-hot account (may succeed as a no-op, but adds unnecessary cost). + +## When deferred execution works safely + +Deferred execution works well when: + +- **Accounts are actively used**: Regular writes keep the virtual rent balance topped up, + preventing accounts from going cold. +- **Your app controls the fee payer**: Your application server pays rent top-ups on every + interaction, keeping accounts hot. +- **Short deferral periods**: The shorter the delay between signing and execution, the less + likely account state changes. + +## When to be cautious + +Avoid deferred execution when: + +- **Accounts may go cold**: If no writes happen for ~24 hours, accounts auto-compress. + A transaction signed before compression will reference stale state. +- **Long deferral periods**: Treasury operations that sit for days or weeks risk account + state changes. +- **Unknown account activity**: If you cannot predict whether the accounts will remain + active, deferred execution is unreliable. + +## Alternative patterns + +For use cases that need delayed execution with Light Token: + +- **Spend permissions**: [Delegate spending](/light-token/payments/advanced/spend-permissions) + to a third party who can execute when ready, loading cold accounts in-flight at execution time. +- **Scheduled execution**: Build and submit the transaction at execution time rather than + pre-signing. This ensures load instructions reflect current account state. + +## Related guides + + + + Delegate token spending with amount caps. + + + Checklist for deploying Light Token in production. + + + + diff --git a/light-token/payments/advanced/spend-permissions.mdx b/light-token/payments/advanced/spend-permissions.mdx new file mode 100644 index 0000000..9e3c63b --- /dev/null +++ b/light-token/payments/advanced/spend-permissions.mdx @@ -0,0 +1,120 @@ +--- +title: "Spend Permissions" +sidebarTitle: "Spend permissions" +description: "Delegate token spending to third parties with amount caps for subscriptions, recurring payments, and managed spending." +keywords: ["delegate tokens solana", "token delegation light token", "spend permissions solana", "recurring payments solana"] +--- + +import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +Delegate token spending to a third party with an amount cap. +The delegate can transfer tokens on behalf of the owner up to the approved amount, +without the owner signing each transaction. + +## Use cases + +| Use case | How delegation helps | +|:---------|:--------------------| +| **Subscriptions** | Approve a monthly cap. The service provider transfers the fee each period. | +| **Recurring payments** | Approve a spending limit. The payment processor draws funds as needed. | +| **Managed spending** | A parent or admin approves a cap for a sub-account. | +| **Agent wallets** | An AI agent operates within a delegated spending limit. | + +## Setup + + + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; + +const rpc = createRpc(RPC_ENDPOINT); +``` + +## Approve a delegate + +Grant a delegate permission to spend up to a capped amount: + +```typescript +import { approve } from "@lightprotocol/compressed-token"; + +const tx = await approve( + rpc, + payer, + mint, + 500, // amount cap + owner, // token owner (signs) + delegate.publicKey // who gets permission +); + +console.log("Approved:", tx); +``` + +## Query delegated accounts + +Check which accounts a delegate has permission to spend: + +```typescript +const delegatedAccounts = await rpc.getCompressedTokenAccountsByDelegate( + delegate.publicKey, + { mint } +); + +console.log("Delegated accounts:", delegatedAccounts.items.length); +``` + +## Revoke a delegate + +Remove spending permission: + +```typescript +import { revoke } from "@lightprotocol/compressed-token"; + +const delegatedAccounts = await rpc.getCompressedTokenAccountsByDelegate( + delegate.publicKey, + { mint } +); + +const tx = await revoke( + rpc, + payer, + delegatedAccounts.items, + owner // owner signs to revoke +); + +console.log("Revoked:", tx); +``` + +## Security considerations + +- **Amount caps**: Always set the minimum amount needed. Delegation does not grant unlimited access. +- **Single delegate**: Each compressed token account supports one active delegate at a time. +- **Monitor usage**: Query `getCompressedTokenAccountsByDelegate` regularly to track delegate activity. +- **Revoke promptly**: Remove delegation when the business relationship ends or the spending period expires. + +## Delegation vs. custody + +| | Delegation | Custody | +|:--|:-----------|:--------| +| **Key control** | Owner retains private key | Third party holds private key | +| **Spending limit** | Capped at approved amount | Unlimited | +| **Revocable** | Owner can revoke at any time | Requires key transfer back | +| **Use case** | Subscriptions, managed spending | Custodial wallets, exchanges | + + +For full TypeScript, Rust, and program-level examples, see the +[approve and revoke cookbook page](/light-token/cookbook/approve-revoke). + + +## Related guides + + + + Sign transactions now, execute later. + + + Separate the fee payer from the token owner. + + + + diff --git a/light-token/payments/interop/wrap-unwrap.mdx b/light-token/payments/interop/wrap-unwrap.mdx new file mode 100644 index 0000000..1efd9c6 --- /dev/null +++ b/light-token/payments/interop/wrap-unwrap.mdx @@ -0,0 +1,167 @@ +--- +title: "Wrap and Unwrap" +sidebarTitle: "Wrap and unwrap" +description: "Move tokens between SPL / Token 2022 and Light Token accounts for CEX on-ramps, off-ramps, and interoperability." +keywords: ["wrap tokens solana", "unwrap tokens solana", "spl to light token", "cex onramp solana", "token interoperability"] +--- + +import RegisterSplMint from "/snippets/setup/register-spl-mint.mdx"; +import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +Wrap moves tokens from an SPL or Token 2022 account into a Light Token associated token account. +Unwrap moves tokens back. Use wrap/unwrap to interoperate with applications that only support +SPL or Token 2022, such as centralized exchanges. + +## When to wrap and unwrap + +| Flow | Use case | +|:-----|:---------| +| **On-ramp** (SPL → Light Token) | User receives USDC from a CEX withdrawal, then wraps to Light Token for cheaper transfers. | +| **Off-ramp** (Light Token → SPL) | User unwraps Light Token USDC to SPL, then deposits to a CEX. | +| **DeFi interop** | Unwrap to use tokens with a protocol that only supports SPL. Wrap back after. | + +## Setup + + + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; + +const rpc = createRpc(RPC_ENDPOINT); +``` + +## Wrap from SPL + + +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/wrap.ts). + + + + + +```typescript +import { Transaction } from "@solana/web3.js"; +import { getAssociatedTokenAddressSync } from "@solana/spl-token"; +import { + createWrapInstruction, + getAssociatedTokenAddressInterface, +} from "@lightprotocol/compressed-token/unified"; +import { getSplInterfaceInfos } from "@lightprotocol/compressed-token"; + +const splAta = getAssociatedTokenAddressSync(mint, owner.publicKey); +const tokenAta = getAssociatedTokenAddressInterface(mint, owner.publicKey); + +const splInterfaceInfos = await getSplInterfaceInfos(rpc, mint); +const splInterfaceInfo = splInterfaceInfos.find((i) => i.isInitialized); + +const tx = new Transaction().add( + createWrapInstruction( + splAta, + tokenAta, + owner.publicKey, + mint, + amount, + splInterfaceInfo, + decimals, + payer.publicKey + ) +); +``` + + + + +```typescript +import { getAssociatedTokenAddressSync } from "@solana/spl-token"; +import { + wrap, + getAssociatedTokenAddressInterface, +} from "@lightprotocol/compressed-token/unified"; + +const splAta = getAssociatedTokenAddressSync(mint, owner.publicKey); +const tokenAta = getAssociatedTokenAddressInterface(mint, owner.publicKey); + +await wrap(rpc, payer, splAta, tokenAta, owner, mint, amount); +``` + + + + +## Unwrap to SPL + + +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/unwrap.ts). + + +Unwrap moves the token balance from a Light Token associated token account to an SPL associated token account. + + + + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { getAssociatedTokenAddressSync } from "@solana/spl-token"; +import { createUnwrapInstructions } from "@lightprotocol/compressed-token/unified"; + +const splAta = getAssociatedTokenAddressSync(mint, owner.publicKey); + +// Each inner array = one transaction. Handles loading + unwrapping together. +const instructions = await createUnwrapInstructions( + rpc, + splAta, + owner.publicKey, + mint, + amount, + payer.publicKey +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + +```typescript +import { getAssociatedTokenAddressSync } from "@solana/spl-token"; +import { unwrap } from "@lightprotocol/compressed-token/unified"; + +const splAta = getAssociatedTokenAddressSync(mint, owner.publicKey); + +await unwrap(rpc, payer, splAta, owner, mint, amount); +``` + + + + +## Register an existing SPL mint + +For existing SPL mints like USDC, register the SPL interface PDA once before wrapping: + + + + +`createMintInterface()` does this automatically when creating new mints. +You only need to register manually for mints that already exist on-chain. + + + +For full TypeScript, Rust, and program-level examples, see the +[wrap and unwrap cookbook page](/light-token/cookbook/wrap-unwrap). + + +## Related guides + + + + Send a single token transfer. + + + Load cold accounts and prepare to receive. + + + + diff --git a/light-token/payments/overview.mdx b/light-token/payments/overview.mdx index 620fce3..63b1050 100644 --- a/light-token/payments/overview.mdx +++ b/light-token/payments/overview.mdx @@ -117,5 +117,22 @@ Learn more on extensions here: [Extensions](https://solana.com/docs/tokens/exten horizontal /> +## Payment guides + + + + Single token transfer with Light Token. + + + Load cold accounts and share your address. + + + Separate the fee payer from the token owner. + + + Checklist for deploying to production. + + + diff --git a/light-token/payments/production-readiness.mdx b/light-token/payments/production-readiness.mdx new file mode 100644 index 0000000..a225494 --- /dev/null +++ b/light-token/payments/production-readiness.mdx @@ -0,0 +1,116 @@ +--- +title: "Production Readiness" +sidebarTitle: "Production readiness" +description: "Checklist for deploying Light Token payment flows to production, including RPC infrastructure, error handling, and security." +keywords: ["production readiness solana", "light token production", "photon indexer", "mainnet deployment solana"] +--- + +import SupportFooter from "/snippets/support-footer.mdx"; + +Checklist and considerations for deploying Light Token payment flows to production. + +## Current status + + +Light Token is in **Beta on Solana devnet**. Mainnet launch is expected in Q1 2026. +For production use today, use [Compressed Tokens V1](/resources/legacy-compressed-tokens), +which are live on Solana mainnet and supported by Phantom and Backpack. + + +## RPC infrastructure + +Light Token requires a Photon-compatible RPC endpoint for cold account lookups and balance queries. + +| Provider | Photon support | Notes | +|:---------|:---------------|:------| +| [Helius](https://helius.dev) | Yes | Recommended. Maintains the Photon indexer. | +| [Triton](https://triton.one) | Yes | Alternative provider. | +| Self-hosted | Yes | Run the [open-source Photon indexer](https://github.com/helius-labs/photon). | + + +If the Photon indexer is temporarily unavailable, hot accounts continue to work normally. +Cold accounts cannot be loaded until the indexer recovers. + + +### Redundant RPC configuration + +For production reliability, configure multiple RPC endpoints: + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; + +// Primary endpoint +const rpc = createRpc(process.env.PRIMARY_RPC_URL); + +// Fallback: switch to secondary if primary fails +const fallbackRpc = createRpc(process.env.SECONDARY_RPC_URL); +``` + +## Transaction landing + +Light Token transactions follow standard Solana patterns for landing: + +- **Priority fees**: Use `ComputeBudgetProgram.setComputeUnitPrice()` to increase transaction priority. +- **Compute units**: Set appropriate compute unit limits with `ComputeBudgetProgram.setComputeUnitLimit()`. +- **Retry logic**: Implement retries with fresh blockhashes for failed transactions. + +## Confirmation levels + +| Level | When to use | +|:------|:------------| +| `processed` | Fastest. Use for UI updates. Not guaranteed to finalize. | +| `confirmed` | Recommended for most payment flows. Confirmed by supermajority of validators. | +| `finalized` | Highest certainty. Use for high-value transfers or irreversible actions. | + +## Error handling + +Handle both standard Solana errors and Light Token-specific scenarios: + +- **Cold account load failures**: Retry the load if the indexer returns stale data. +- **Associated token account creation**: Idempotent — safe to retry. +- **Rent top-up failures**: Ensure the fee payer has sufficient SOL balance. +- **Transaction size limits**: If `TransactionInstruction[][]` returns multiple batches, process them sequentially. + +## Fee sponsorship + +Set your application as the fee payer so users never interact with SOL: + +1. **Rent top-ups**: Set `payer` parameter on Light Token instructions. See [fee abstraction](/light-token/payments/send-payments/fee-abstraction). +2. **Transaction fees**: Use standard Solana fee payer patterns or services like [Kora](https://github.com/nicholasgasior/kora). +3. **Rent sponsor funding**: Ensure the rent sponsor PDA is funded. See [sponsor rent top-ups](/light-token/wallets/sponsor-top-ups). + +## Security + +- **Key management**: Use hardware security modules (HSMs) or managed key services for production signing keys. +- **Signing infrastructure**: Separate hot wallets (for automated operations) from cold wallets (for treasury). +- **Address verification**: Validate recipient addresses before sending. See [verify address](/light-token/payments/send-payments/verify-address). +- **Monitoring**: Track transaction success rates, cold account loading frequency, and fee payer SOL balance. + +## Pre-launch checklist + +- [ ] Photon-compatible RPC endpoint configured and tested +- [ ] Redundant RPC endpoint available for failover +- [ ] Fee payer wallet funded with sufficient SOL +- [ ] Cold account loading tested end-to-end +- [ ] Error handling covers load failures, tx size limits, and retries +- [ ] Confirmation level appropriate for your use case +- [ ] Address verification implemented +- [ ] Monitoring and alerting set up +- [ ] Wrap/unwrap flows tested for CEX interoperability (if applicable) +- [ ] Delegation (spend permissions) tested and revocation verified (if applicable) + +## Related guides + + + + Abstract fees for users. + + + Send a single transfer. + + + Load cold accounts and prepare to receive. + + + + diff --git a/light-token/payments/send-payments/basic-payment.mdx b/light-token/payments/send-payments/basic-payment.mdx new file mode 100644 index 0000000..0fd8f4b --- /dev/null +++ b/light-token/payments/send-payments/basic-payment.mdx @@ -0,0 +1,196 @@ +--- +title: "Basic Payment" +sidebarTitle: "Basic payment" +description: "Send a single token transfer with Light Token." +keywords: ["stablecoin transfer solana", "light token transfer", "send payment solana", "rent free transfer"] +--- + +import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +Send a single token transfer between two wallets. The Light Token transfer API mirrors SPL but handles +cold account loading and associated token account creation automatically. + + +Find full runnable code examples: +[instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/send-instruction.ts) | +[action](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/send-action.ts). + + +## How it works + +1. The SDK checks whether the sender's account has a cold balance and adds load instructions if needed. +2. If the recipient does not have a Light Token associated token account, the SDK creates one. +3. The transfer executes atomically. + +APIs return `TransactionInstruction[][]` — an array of transaction batches. Almost always a single +transaction, but the loop pattern handles the rare multi-transaction case automatically. + +## Setup + + + +Snippets below assume `rpc`, `payer`, `mint`, `owner`, `recipient`, and `amount` are defined. +See the [full examples](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets) for runnable setup. + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; + +const rpc = createRpc(RPC_ENDPOINT); +``` + +## Send a payment + + + + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +// Returns TransactionInstruction[][]. +// Each inner array is one transaction. +// Almost always returns just one. +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + +Your app logic may require you to create a single sign request for your user: + +```typescript +const transactions = instructions.map((ixs) => new Transaction().add(...ixs)); + +// One approval for all +const signed = await wallet.signAllTransactions(transactions); + +for (const tx of signed) { + await sendAndConfirmTransaction(rpc, tx); +} +``` + + + + + +While almost always you will have only one transfer transaction, you can +optimize sending in the rare cases where you have multiple transactions. +Parallelize the loads, confirm them, and then send the transfer instruction +after. + +```typescript +import { + createTransferInterfaceInstructions, + sliceLast, +} from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); +const { rest: loadInstructions, last: transferInstructions } = sliceLast(instructions); +// empty = nothing to load, will no-op. +await Promise.all( + loadInstructions.map((ixs) => { + const tx = new Transaction().add(...ixs); + tx.sign(payer, owner); + return sendAndConfirmTransaction(rpc, tx); + }) +); + +const transferTx = new Transaction().add(...transferInstructions); +transferTx.sign(payer, owner); +await sendAndConfirmTransaction(rpc, transferTx); +``` + + + + + +```typescript +import { + getAssociatedTokenAddressSync, + createAssociatedTokenAccountIdempotentInstruction, + createTransferInstruction, +} from "@solana/spl-token"; + +const sourceAta = getAssociatedTokenAddressSync(mint, owner.publicKey); +const destinationAta = getAssociatedTokenAddressSync(mint, recipient); + +const tx = new Transaction().add( + createAssociatedTokenAccountIdempotentInstruction( + payer.publicKey, destinationAta, recipient, mint + ), + createTransferInstruction(sourceAta, destinationAta, owner.publicKey, amount) +); +``` + + + + + + +```typescript +import { + getAssociatedTokenAddressInterface, + transferInterface, +} from "@lightprotocol/compressed-token/unified"; + +const sourceAta = getAssociatedTokenAddressInterface(mint, owner.publicKey); + +// Handles loading, creates recipient associated token account, transfers. +await transferInterface(rpc, payer, sourceAta, mint, recipient, owner, amount); +``` + + + +```typescript +import { + getAssociatedTokenAddressSync, + getOrCreateAssociatedTokenAccount, + transfer, +} from "@solana/spl-token"; + +await getOrCreateAssociatedTokenAccount(connection, payer, mint, recipient); + +const sourceAta = getAssociatedTokenAddressSync(mint, owner.publicKey); +const destinationAta = getAssociatedTokenAddressSync(mint, recipient); +await transfer(connection, payer, sourceAta, destinationAta, owner, amount); +``` + + + + + + +## Related guides + + + + Handle multi-transaction batches and multiple recipients. + + + Separate the fee payer from the token owner. + + + Load cold accounts and prepare to receive. + + + + diff --git a/light-token/payments/send-payments/batch-payments.mdx b/light-token/payments/send-payments/batch-payments.mdx new file mode 100644 index 0000000..cb50eb7 --- /dev/null +++ b/light-token/payments/send-payments/batch-payments.mdx @@ -0,0 +1,179 @@ +--- +title: "Batch Payments" +sidebarTitle: "Batch payments" +description: "Handle multi-transaction batches and send payments to multiple recipients." +keywords: ["batch payments solana", "multiple transfers solana", "light token batch", "signAndSendBatches"] +--- + +import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +Handle the `TransactionInstruction[][]` pattern that Light Token APIs return, +and send payments to multiple recipients. + + +**How Light Token batching differs from SPL**: SPL batching puts multiple transfer instructions +in a single transaction. Light Token APIs return `TransactionInstruction[][]` because +cold accounts may need loading before the transfer can execute. Each inner array is one +atomic transaction. Almost always a single transaction, but the pattern handles multi-transaction +cases automatically. + + +## Setup + + + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; + +const rpc = createRpc(RPC_ENDPOINT); +``` + +## Handle instruction batches + +Every Light Token API that modifies state returns `TransactionInstruction[][]`. +The standard loop handles all cases: + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + +## Parallelize load transactions + +When the SDK returns multiple transaction batches (load + transfer), you can +parallelize the load transactions and send the transfer last: + +```typescript +import { + createTransferInterfaceInstructions, + sliceLast, +} from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +const { rest: loadInstructions, last: transferInstructions } = sliceLast(instructions); + +// Parallelize loads (empty = nothing to load, will no-op) +await Promise.all( + loadInstructions.map((ixs) => { + const tx = new Transaction().add(...ixs); + tx.sign(payer, owner); + return sendAndConfirmTransaction(rpc, tx); + }) +); + +// Send transfer after all loads confirm +const transferTx = new Transaction().add(...transferInstructions); +transferTx.sign(payer, owner); +await sendAndConfirmTransaction(rpc, transferTx); +``` + +## Helper: signAndSendBatches + +For wallet integrations (Privy, Wallet Adapter), use a shared helper +that handles blockhash, signing, sending, and confirming for each batch: + +```typescript +import { Transaction, TransactionInstruction, PublicKey } from "@solana/web3.js"; + +async function signAndSendBatches( + instructionBatches: TransactionInstruction[][], + rpc: any, + feePayer: PublicKey, + signTransaction: (tx: Transaction) => Promise +): Promise { + const signatures: string[] = []; + + for (const ixs of instructionBatches) { + const tx = new Transaction().add(...ixs); + const { blockhash } = await rpc.getLatestBlockhash(); + tx.recentBlockhash = blockhash; + tx.feePayer = feePayer; + + const signedTx = await signTransaction(tx); + const sig = await rpc.sendRawTransaction(signedTx.serialize(), { + skipPreflight: false, + preflightCommitment: "confirmed", + }); + await rpc.confirmTransaction(sig, "confirmed"); + signatures.push(sig); + } + + return signatures.length > 0 ? signatures[signatures.length - 1] : null; +} +``` + + +See the complete implementation in the +[Privy integration](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/sign-with-privy/react/src/hooks/signAndSendBatches.ts) and +[Wallet Adapter integration](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter) examples. + + +## Send to multiple recipients + +Call `createTransferInterfaceInstructions()` per recipient and process sequentially: + +```typescript +const recipients = [ + { address: recipientA, amount: 100 }, + { address: recipientB, amount: 200 }, + { address: recipientC, amount: 300 }, +]; + +for (const { address, amount } of recipients) { + const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + address + ); + + for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); + } +} +``` + + +When all accounts are hot (no loading needed), multiple transfer instructions can fit in a single +Solana transaction. However, the SDK does not batch multi-recipient transfers natively — call +`createTransferInterfaceInstructions()` per recipient. + + +## Related guides + + + + Send a single transfer. + + + Separate the fee payer from the token owner. + + + + diff --git a/light-token/payments/send-payments/fee-abstraction.mdx b/light-token/payments/send-payments/fee-abstraction.mdx new file mode 100644 index 0000000..8e0618a --- /dev/null +++ b/light-token/payments/send-payments/fee-abstraction.mdx @@ -0,0 +1,95 @@ +--- +title: "Fee Abstraction" +sidebarTitle: "Fee abstraction" +description: "Abstract fees so users never interact with SOL. Separate the fee payer from the token owner." +keywords: ["fee abstraction solana", "gasless transfer solana", "rent sponsorship light token", "sponsor rent solana"] +--- + +import RentSponsorship from "/snippets/rent-sponsorship-explained.mdx"; +import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +Light Token provides built-in rent sponsorship. Set a separate `payer` from the `authority` so your +application covers rent top-ups while users only sign to authorize their transfers. + + +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/sponsor-rent-top-ups/typescript/sponsor-top-ups.ts). + + +## How fee sponsorship works + +Light Token transfers accept two distinct roles: + +| Role | Parameter | What it does | +|:-----|:----------|:-------------| +| **Payer** (fee payer) | First positional arg | Pays rent top-ups to keep accounts active. Can be your application server. | +| **Authority** (owner) | `owner` / authority arg | Signs to authorize the token transfer. The account holder. | + +When payer and authority are different, both must sign the transaction. + +## Rent sponsorship + + + +## Setup + + + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; + +const rpc = createRpc(RPC_ENDPOINT); +``` + +## Send with a separate fee payer + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +// Sponsor covers rent top-ups, sender authorizes the transfer. +const instructions = await createTransferInterfaceInstructions( + rpc, + sponsor.publicKey, // payer: covers rent top-ups + mint, + amount, + sender.publicKey, // authority: user signs to authorize + recipient.publicKey +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + // Both sponsor and sender must sign + await sendAndConfirmTransaction(rpc, tx, [sponsor, sender]); +} +``` + + +This covers **rent fee abstraction** — your app pays the small rent top-ups (766 lamports by default per write). +For **transaction fee abstraction** (paying the Solana base fee on behalf of users), see [Solana's fee abstraction patterns](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction). + + + + +Solana's standard fee abstraction uses [Kora](https://github.com/nicholasgasior/kora) to sponsor transaction fees. +Light Token handles rent natively — the `payer` parameter on any Light Token instruction determines who pays rent top-ups. +No external service is needed for rent sponsorship. + +For a complete fee-free user experience, combine both: +1. Light Token's `payer` parameter for rent top-ups +2. Standard Solana fee payer for transaction base fees + + + +## Related guides + + + + Detailed setup guide for wallet-based rent sponsorship. + + + Send a single token transfer. + + + + diff --git a/light-token/payments/send-payments/payment-with-memo.mdx b/light-token/payments/send-payments/payment-with-memo.mdx new file mode 100644 index 0000000..526cde8 --- /dev/null +++ b/light-token/payments/send-payments/payment-with-memo.mdx @@ -0,0 +1,109 @@ +--- +title: "Payment with Memo" +sidebarTitle: "Payment with memo" +description: "Attach invoice IDs, payment references, or notes to Light Token transfers using the memo program." +keywords: ["memo payment solana", "invoice reconciliation solana", "payment reference light token", "memo instruction"] +--- + +import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +Attach metadata like invoice IDs or payment references to a Light Token transfer +using Solana's memo program. The memo is recorded in the transaction logs for reconciliation. + + +The memo program is a standard Solana program that works with any transaction. +Adding a memo instruction alongside a Light Token transfer should work, but verify +on devnet before using in production. + + +## How it works + +1. Create the transfer instructions with `createTransferInterfaceInstructions()`. +2. Add a memo instruction to the transfer transaction (the last batch). +3. Both instructions execute atomically in the same transaction. + +## Setup + + + +Additionally install the memo program package: + +```bash +npm install @solana/spl-memo +``` + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; + +const rpc = createRpc(RPC_ENDPOINT); +``` + +## Send a payment with memo + +```typescript +import { Transaction, sendAndConfirmTransaction, TransactionInstruction, PublicKey } from "@solana/web3.js"; +import { + createTransferInterfaceInstructions, + sliceLast, +} from "@lightprotocol/compressed-token/unified"; + +const MEMO_PROGRAM_ID = new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"); + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +const { rest: loadInstructions, last: transferInstructions } = sliceLast(instructions); + +// Send load transactions first (if any) +for (const ixs of loadInstructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} + +// Add memo to the transfer transaction +const memoIx = new TransactionInstruction({ + keys: [], + programId: MEMO_PROGRAM_ID, + data: Buffer.from("INV-2024-001"), +}); + +const transferTx = new Transaction().add(...transferInstructions, memoIx); +await sendAndConfirmTransaction(rpc, transferTx, [payer, owner]); +``` + +## Read memo from transaction logs + +After the transaction confirms, the memo appears in the transaction logs: + +```typescript +const txDetails = await rpc.getTransaction(signature, { + maxSupportedTransactionVersion: 0, +}); + +// Look for memo program log entries +const logs = txDetails?.meta?.logMessages || []; +const memoLogs = logs.filter((log) => + log.includes("Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr") +); +console.log("Memo logs:", memoLogs); +``` + +## Related guides + + + + Send a single transfer without memo. + + + Query balances and transaction history. + + + + diff --git a/light-token/payments/send-payments/verify-address.mdx b/light-token/payments/send-payments/verify-address.mdx new file mode 100644 index 0000000..c0e67a5 --- /dev/null +++ b/light-token/payments/send-payments/verify-address.mdx @@ -0,0 +1,80 @@ +--- +title: "Verify Address" +sidebarTitle: "Verify address" +description: "Validate recipient addresses before sending payments to prevent lost funds." +keywords: ["verify address solana", "address validation light token", "solana address check", "payment safety"] +--- + +import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +Verify recipient addresses before sending payments. +Address validation prevents sending tokens to invalid or unexpected account types. + +## Understanding Solana addresses + +Solana has two types of addresses: + +- **On-curve addresses** (wallets): derived from a keypair, can sign transactions. +- **Off-curve addresses** (PDAs): program-derived addresses, cannot sign transactions. + +## Account types in payments + +When validating a recipient, check what type of account the address belongs to: + +| Type | Description | Safe to send? | +|:-----|:------------|:--------------| +| **Wallet** | Standard keypair address, no on-chain account or a system account | Yes | +| **Light Token associated token account** | An associated token account for the target mint | Yes | +| **Token account (wrong mint)** | An associated token account for a different mint | No | +| **Program or PDA** | A program-owned account or program-derived address | Depends on use case | + +## Verification flow + +Before sending a payment: + +1. Check if the address is on-curve (wallet) or off-curve (PDA). +2. If the address has an on-chain account, check the account owner and type. +3. For Light Token, derive the associated token account to verify it matches the expected mint. + +```typescript +import { + getAssociatedTokenAddressInterface, + getAtaInterface, +} from "@lightprotocol/compressed-token/unified"; + +// Derive the expected associated token account for this recipient and mint +const expectedAta = getAssociatedTokenAddressInterface(mint, recipientWallet); + +// Check if the account exists and is active +try { + const account = await getAtaInterface(rpc, expectedAta, recipientWallet, mint); + console.log("Account exists, balance:", account.parsed.amount); +} catch { + console.log("Account does not exist yet — will be created on first transfer"); +} +``` + + +Use `getAssociatedTokenAddressInterface()` instead of SPL's `getAssociatedTokenAddressSync()` to derive +Light Token associated token account addresses. The derivation uses the Light Token Program ID. + + + +When you send a payment with `transferInterface()` or `createTransferInterfaceInstructions()`, +the SDK automatically creates the recipient's associated token account if it doesn't exist. +Address verification is a safety check, not a prerequisite. + + +## Related guides + + + + Send a single token transfer. + + + Load cold accounts and prepare to receive. + + + + From 5440ad619fe17d343f82b0170529a2d650410637 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Wed, 18 Mar 2026 01:23:49 +0000 Subject: [PATCH 02/19] Remove spend-permissions from payments nav and fix references Delegation (approve/revoke) not yet supported on Light Token associated token accounts. Remove from nav and cross-links until SDK exposes interface functions for hot accounts. --- docs.json | 1 - light-token/payments/advanced/deferred-execution.mdx | 6 ++---- light-token/payments/production-readiness.mdx | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs.json b/docs.json index bee9c97..8977828 100644 --- a/docs.json +++ b/docs.json @@ -78,7 +78,6 @@ { "group": "Advanced", "pages": [ - "light-token/payments/advanced/spend-permissions", "light-token/payments/advanced/deferred-execution" ] }, diff --git a/light-token/payments/advanced/deferred-execution.mdx b/light-token/payments/advanced/deferred-execution.mdx index 4caa11c..339f80e 100644 --- a/light-token/payments/advanced/deferred-execution.mdx +++ b/light-token/payments/advanced/deferred-execution.mdx @@ -61,16 +61,14 @@ Avoid deferred execution when: For use cases that need delayed execution with Light Token: -- **Spend permissions**: [Delegate spending](/light-token/payments/advanced/spend-permissions) - to a third party who can execute when ready, loading cold accounts in-flight at execution time. - **Scheduled execution**: Build and submit the transaction at execution time rather than pre-signing. This ensures load instructions reflect current account state. ## Related guides - - Delegate token spending with amount caps. + + Separate the fee payer from the token owner. Checklist for deploying Light Token in production. diff --git a/light-token/payments/production-readiness.mdx b/light-token/payments/production-readiness.mdx index a225494..5225fb3 100644 --- a/light-token/payments/production-readiness.mdx +++ b/light-token/payments/production-readiness.mdx @@ -97,7 +97,7 @@ Set your application as the fee payer so users never interact with SOL: - [ ] Address verification implemented - [ ] Monitoring and alerting set up - [ ] Wrap/unwrap flows tested for CEX interoperability (if applicable) -- [ ] Delegation (spend permissions) tested and revocation verified (if applicable) +- [ ] Wrap/unwrap flows tested for SPL interoperability ## Related guides From 1af67d1189cd1487046267a056b804e023eb5138 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Wed, 18 Mar 2026 02:11:54 +0000 Subject: [PATCH 03/19] =?UTF-8?q?Rename=20sponsor-top-ups=20=E2=86=92=20ga?= =?UTF-8?q?sless-transactions=20across=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename page, snippets, nav entries, redirects, and all cross-references. Add redirect from old URL. Update descriptions to "Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees." --- README.md | 1 + docs.json | 8 +++- faq.mdx | 8 ++-- .../accept-payments/receive-payments.mdx | 2 +- light-token/payments/integration-guide.mdx | 2 +- light-token/payments/overview.mdx | 2 +- light-token/payments/production-readiness.mdx | 2 +- .../send-payments/fee-abstraction.mdx | 4 +- light-token/wallets/gasless-transactions.mdx | 43 +++++++++++++++++++ light-token/wallets/overview.mdx | 2 +- light-token/wallets/sponsor-top-ups.mdx | 43 ------------------- light-token/welcome.mdx | 4 +- skill.md | 2 +- snippets/ai-prompts/all-prompts.mdx | 8 ++-- ...r-top-ups.mdx => gasless-transactions.mdx} | 14 +++--- .../rust-instruction.mdx | 0 .../ts-instruction.mdx | 0 .../light-token-client-examples-table.mdx | 2 +- 18 files changed, 76 insertions(+), 71 deletions(-) create mode 100644 light-token/wallets/gasless-transactions.mdx delete mode 100644 light-token/wallets/sponsor-top-ups.mdx rename snippets/ai-prompts/wallets/{sponsor-top-ups.mdx => gasless-transactions.mdx} (94%) rename snippets/code-snippets/light-token/{sponsor-rent-top-ups => gasless-transactions}/rust-instruction.mdx (100%) rename snippets/code-snippets/light-token/{sponsor-rent-top-ups => gasless-transactions}/ts-instruction.mdx (100%) diff --git a/README.md b/README.md index 7b0350d..3f35c31 100644 --- a/README.md +++ b/README.md @@ -8,5 +8,6 @@ Resources for developers to learn and build: Find more resources here: - Documentation: [zkcompression.com](https://www.zkcompression.com). +- Index for LLMs and Agents: [llms.txt](https://www.zkcompression.com/llms.txt) - [Examples](https://github.com/Lightprotocol/examples-light-token) - [Agent Skills](https://github.com/Lightprotocol/skills/tree/main) diff --git a/docs.json b/docs.json index 8977828..0b6f53f 100644 --- a/docs.json +++ b/docs.json @@ -91,7 +91,7 @@ "light-token/wallets/overview", "light-token/wallets/privy", "light-token/wallets/wallet-adapter", - "light-token/wallets/sponsor-top-ups" + "light-token/wallets/gasless-transactions" ] }, { @@ -960,7 +960,11 @@ }, { "source": "/light-token/toolkits/sponsor-top-ups", - "destination": "https://zkcompression.com/light-token/wallets/sponsor-top-ups" + "destination": "https://zkcompression.com/light-token/wallets/gasless-transactions" + }, + { + "source": "/light-token/wallets/sponsor-top-ups", + "destination": "https://zkcompression.com/light-token/wallets/gasless-transactions" }, { "source": "/light-token/toolkits/for-streaming-mints", diff --git a/faq.mdx b/faq.mdx index 3d639d7..29d646d 100644 --- a/faq.mdx +++ b/faq.mdx @@ -30,9 +30,9 @@ This is dealt with under the hood in a way that doesn’t disrupt the UX of what - + -Set the `payer` parameter to the sponsor's public key on any Light Token instruction. The sponsor pays SOL for rent top-ups while the user only signs to authorize the transfer. +Set the `payer` parameter to the sponsor's public key on any Light Token instruction. The sponsor pays SOL for rent top-ups and transaction fees while the user only signs to authorize the transfer. ```typescript const ix = createLightTokenTransferInstruction( @@ -40,13 +40,13 @@ const ix = createLightTokenTransferInstruction( recipientAta, sender.publicKey, amount, - sponsor.publicKey, // sponsor pays rent top-ups + sponsor.publicKey, // sponsor pays rent top-ups and transaction fees ); await sendAndConfirmTransaction(rpc, tx, [sponsor, sender]); ``` - + diff --git a/light-token/payments/accept-payments/receive-payments.mdx b/light-token/payments/accept-payments/receive-payments.mdx index e55a36d..6584f5d 100644 --- a/light-token/payments/accept-payments/receive-payments.mdx +++ b/light-token/payments/accept-payments/receive-payments.mdx @@ -128,7 +128,7 @@ const ata = await getOrCreateAssociatedTokenAccount( Check balances and transaction history. - Sponsor rent top-ups so users never pay SOL. + Abstract SOL fees so users never hold SOL. diff --git a/light-token/payments/integration-guide.mdx b/light-token/payments/integration-guide.mdx index 00553c5..e761a80 100644 --- a/light-token/payments/integration-guide.mdx +++ b/light-token/payments/integration-guide.mdx @@ -502,7 +502,7 @@ await unwrap(rpc, payer, splAta, owner, mint, amount); ## Related Guides - + Abstract fees entirely so users never interact with SOL. diff --git a/light-token/payments/overview.mdx b/light-token/payments/overview.mdx index 63b1050..30eee2a 100644 --- a/light-token/payments/overview.mdx +++ b/light-token/payments/overview.mdx @@ -48,7 +48,7 @@ The token standard pays rent-exemption cost for you. To prevent griefing, “ren You can abstract fees entirely so users never interact with SOL. - See [fee abstraction](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction) for transaction fees. -- See [sponsor rent top-ups](/light-token/wallets/sponsor-top-ups). +- See [gasless transactions](/light-token/wallets/gasless-transactions). ## API Comparison diff --git a/light-token/payments/production-readiness.mdx b/light-token/payments/production-readiness.mdx index 5225fb3..9cdddb8 100644 --- a/light-token/payments/production-readiness.mdx +++ b/light-token/payments/production-readiness.mdx @@ -77,7 +77,7 @@ Set your application as the fee payer so users never interact with SOL: 1. **Rent top-ups**: Set `payer` parameter on Light Token instructions. See [fee abstraction](/light-token/payments/send-payments/fee-abstraction). 2. **Transaction fees**: Use standard Solana fee payer patterns or services like [Kora](https://github.com/nicholasgasior/kora). -3. **Rent sponsor funding**: Ensure the rent sponsor PDA is funded. See [sponsor rent top-ups](/light-token/wallets/sponsor-top-ups). +3. **Rent sponsor funding**: Ensure the rent sponsor PDA is funded. See [gasless transactions](/light-token/wallets/gasless-transactions). ## Security diff --git a/light-token/payments/send-payments/fee-abstraction.mdx b/light-token/payments/send-payments/fee-abstraction.mdx index 8e0618a..60bc7d5 100644 --- a/light-token/payments/send-payments/fee-abstraction.mdx +++ b/light-token/payments/send-payments/fee-abstraction.mdx @@ -13,7 +13,7 @@ Light Token provides built-in rent sponsorship. Set a separate `payer` from the application covers rent top-ups while users only sign to authorize their transfers. -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/sponsor-rent-top-ups/typescript/sponsor-top-ups.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/gasless-transactions/typescript/gasless-transfer.ts). ## How fee sponsorship works @@ -84,7 +84,7 @@ For a complete fee-free user experience, combine both: ## Related guides - + Detailed setup guide for wallet-based rent sponsorship. diff --git a/light-token/wallets/gasless-transactions.mdx b/light-token/wallets/gasless-transactions.mdx new file mode 100644 index 0000000..86b4225 --- /dev/null +++ b/light-token/wallets/gasless-transactions.mdx @@ -0,0 +1,43 @@ +--- +title: Gasless Transactions +description: Abstract SOL fees so users never hold SOL. Set your application as the fee payer to sponsor rent top-ups and transaction fees. +keywords: ["gasless transactions solana", "rent sponsorship solana", "fee abstraction light token", "gasless solana tokens", "rent free tokens on solana"] +--- + +import TransferInstructionCode from "/snippets/code-snippets/light-token/gasless-transactions/ts-instruction.mdx"; +import RustInstructionCode from "/snippets/code-snippets/light-token/gasless-transactions/rust-instruction.mdx"; +import RentSponsorshipExplained from "/snippets/rent-sponsorship-explained.mdx"; +import GaslessTransactionsAiPrompt from "/snippets/ai-prompts/wallets/gasless-transactions.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +--- + + +Rent sponsorship is a built-in feature of the Light SDK’s that sponsors rent-exemption for all account types to reduce creation cost. +This is dealt with under the hood in a way that doesn’t disrupt the UX of what your users are used to with SPL-token. + + + + +## How to sponsor rent top-ups and transaction fees + +Set the `payer` parameter to the sponsor’s public key when calling `createTransferInterfaceInstructions` (TypeScript) or building a `TransferInterface` instruction (Rust). The sponsor pays SOL for rent top-ups and transaction fees while the user only signs to authorize the transfer. + + +You can set the payer to any signing account on any Light Token transaction. + + + + + + + + + + + + + + + + diff --git a/light-token/wallets/overview.mdx b/light-token/wallets/overview.mdx index 04959d7..2b307d9 100644 --- a/light-token/wallets/overview.mdx +++ b/light-token/wallets/overview.mdx @@ -449,7 +449,7 @@ await unwrap(rpc, payer, splAta, owner, mint, amount); - + diff --git a/light-token/wallets/sponsor-top-ups.mdx b/light-token/wallets/sponsor-top-ups.mdx deleted file mode 100644 index 7089be5..0000000 --- a/light-token/wallets/sponsor-top-ups.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Sponsor Rent Top-Ups for Users -description: The Light SDK sponsors rent-exemption for Solana accounts and keeps accounts active through periodic top-ups paid by the fee payer. Sponsor top-ups by setting your application as the fee payer to abstract away holding SOL from your users or provide a rent-free experience similar to transaction fee sponsorship. -keywords: ["rent free tokens on solana", "rent sponsorship solana", "rent exemption solana", "light token rent", "gasless solana tokens"] ---- - -import TransferInstructionCode from "/snippets/code-snippets/light-token/sponsor-rent-top-ups/ts-instruction.mdx"; -import RustInstructionCode from "/snippets/code-snippets/light-token/sponsor-rent-top-ups/rust-instruction.mdx"; -import RentSponsorshipExplained from "/snippets/rent-sponsorship-explained.mdx"; -import SponsorTopUpsAiPrompt from "/snippets/ai-prompts/wallets/sponsor-top-ups.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; - ---- - - -Rent sponsorship is a built-in feature of the Light SDK’s that sponsors rent-exemption for all account types to reduce creation cost. -This is dealt with under the hood in a way that doesn’t disrupt the UX of what your users are used to with SPL-token. - - - - -## How to use Sponsored Rent Top-Ups for Accounts and Transfers - -To sponsor rent top-ups for your users, set the `payer` parameter to the sponsor’s public key when calling `createTransferInterfaceInstructions` (TypeScript) or building a `TransferInterface` instruction (Rust). The sponsor pays SOL for any rent top-ups while the user only signs to authorize the transfer. - - -You can set the payer to any signing account on any Light Token transaction. - - - - - - - - - - - - - - - - diff --git a/light-token/welcome.mdx b/light-token/welcome.mdx index e927310..0cab3f6 100644 --- a/light-token/welcome.mdx +++ b/light-token/welcome.mdx @@ -212,8 +212,8 @@ View the [guide](/light-token/cookbook/create-ata) to create associated token ac Build and sign transactions using the Solana Wallet Adapter. - - Sponsor rent top-ups from users to abstract away holding SOL and provide a rent-free experience. + + Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees. diff --git a/skill.md b/skill.md index e063a0a..4b4c365 100644 --- a/skill.md +++ b/skill.md @@ -178,7 +178,7 @@ Use rent-free PDAs for: user state, app state, nullifiers for payments, DePIN no | [Payments and Wallets](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets) | All you need for wallet integrations and payment flows. Minimal API differences to SPL. | | [Streaming Tokens](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/streaming-tokens/) | Stream mint events using Laserstream | | [Sign with Privy](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy/) | Light-token operations signed with Privy wallets (Node.js + React) | -| [Sponsor Rent Top-Ups](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sponsor-rent-top-ups/) | Sponsor rent top-ups for users by setting your application as the fee payer | +| [Gasless Transactions](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions/) | Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees. | ### TypeScript client (`@lightprotocol/compressed-token`) diff --git a/snippets/ai-prompts/all-prompts.mdx b/snippets/ai-prompts/all-prompts.mdx index 9a3cce9..3363817 100644 --- a/snippets/ai-prompts/all-prompts.mdx +++ b/snippets/ai-prompts/all-prompts.mdx @@ -29,7 +29,7 @@ import Airdrop from "/snippets/ai-prompts/toolkits/airdrop.mdx"; {/* wallets */} import WalletAdapter from "/snippets/ai-prompts/wallets/wallet-adapter.mdx"; import Privy from "/snippets/ai-prompts/wallets/privy.mdx"; -import SponsorTopUps from "/snippets/ai-prompts/wallets/sponsor-top-ups.mdx"; +import GaslessTransactions from "/snippets/ai-prompts/wallets/gasless-transactions.mdx"; {/* migration */} import V1ToV2Migration from "/snippets/ai-prompts/v1-to-v2-migration.mdx"; @@ -96,9 +96,9 @@ Copy the prompt below or view the [guide](/light-token/wallets/privy). - -Copy the prompt below or view the [guide](/light-token/wallets/sponsor-top-ups). - + +Copy the prompt below or view the [guide](/light-token/wallets/gasless-transactions). + ## Light-PDA diff --git a/snippets/ai-prompts/wallets/sponsor-top-ups.mdx b/snippets/ai-prompts/wallets/gasless-transactions.mdx similarity index 94% rename from snippets/ai-prompts/wallets/sponsor-top-ups.mdx rename to snippets/ai-prompts/wallets/gasless-transactions.mdx index 9cf76b5..319efc2 100644 --- a/snippets/ai-prompts/wallets/sponsor-top-ups.mdx +++ b/snippets/ai-prompts/wallets/gasless-transactions.mdx @@ -1,13 +1,13 @@ - + {`--- -description: Sponsor rent top-ups for Light Token users +description: Gasless transactions for Light Token users allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression --- -## Sponsor rent top-ups for Light Token users +## Gasless transactions for Light Token users Context: -- Guide: https://zkcompression.com/light-token/wallets/sponsor-top-ups +- Guide: https://zkcompression.com/light-token/wallets/gasless-transactions - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison - Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets @@ -74,14 +74,14 @@ Key APIs: ```text --- -description: Sponsor rent top-ups for Light Token users +description: Gasless transactions for Light Token users allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression --- -## Sponsor rent top-ups for Light Token users +## Gasless transactions for Light Token users Context: -- Guide: https://zkcompression.com/light-token/wallets/sponsor-top-ups +- Guide: https://zkcompression.com/light-token/wallets/gasless-transactions - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison - Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets diff --git a/snippets/code-snippets/light-token/sponsor-rent-top-ups/rust-instruction.mdx b/snippets/code-snippets/light-token/gasless-transactions/rust-instruction.mdx similarity index 100% rename from snippets/code-snippets/light-token/sponsor-rent-top-ups/rust-instruction.mdx rename to snippets/code-snippets/light-token/gasless-transactions/rust-instruction.mdx diff --git a/snippets/code-snippets/light-token/sponsor-rent-top-ups/ts-instruction.mdx b/snippets/code-snippets/light-token/gasless-transactions/ts-instruction.mdx similarity index 100% rename from snippets/code-snippets/light-token/sponsor-rent-top-ups/ts-instruction.mdx rename to snippets/code-snippets/light-token/gasless-transactions/ts-instruction.mdx diff --git a/snippets/overview-tables/light-token-client-examples-table.mdx b/snippets/overview-tables/light-token-client-examples-table.mdx index df2a937..1c610a2 100644 --- a/snippets/overview-tables/light-token-client-examples-table.mdx +++ b/snippets/overview-tables/light-token-client-examples-table.mdx @@ -5,7 +5,7 @@ | **payments-and-wallets** | All you need for wallet integrations and payment flows. Minimal API differences to SPL. | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets) \| [Docs](/light-token/payments/integration-guide) | | **sign-with-privy** | Light-token operations signed with Privy wallets (Node.js + React) | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy) \| [Docs](/light-token/wallets/privy) | | **sign-with-wallet-adapter** | Light-token operations signed with Wallet Adapter (React) | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter) \| [Docs](/light-token/wallets/wallet-adapter) | -| **sponsor-rent-top-ups** | Sponsor rent top-ups by setting your application as the fee payer | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sponsor-rent-top-ups) \| [Docs](/light-token/wallets/sponsor-top-ups) | +| **gasless-transactions** | Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees. | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions) \| [Docs](/light-token/wallets/gasless-transactions) | | **spl-to-light** | Transfer from SPL to Light via TransferInterface | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/instructions/spl_to_light_transfer.rs) | ### TypeScript From 8e4f3ab4a09e97830ac1df46fad6e724368b09eb Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Thu, 19 Mar 2026 00:46:59 +0000 Subject: [PATCH 04/19] add payment --- docs.json | 32 +- light-token/defi/programs-pinocchio.mdx | 2 - light-token/defi/programs.mdx | 2 - light-token/defi/routers.mdx | 2 - .../payments/advanced/deferred-execution.mdx | 78 ---- .../{send-payments => }/basic-payment.mdx | 140 +++++--- light-token/payments/batch-payments.mdx | 220 ++++++++++++ light-token/payments/overview.mdx | 57 ++- .../{send-payments => }/payment-with-memo.mdx | 48 ++- light-token/payments/production-readiness.mdx | 69 ++-- .../receive-payments.mdx | 56 ++- .../payments/send-payments/batch-payments.mdx | 179 --------- .../send-payments/fee-abstraction.mdx | 95 ----- .../{advanced => }/spend-permissions.mdx | 91 +++-- .../{accept-payments => }/verify-payments.mdx | 54 ++- ...dress.mdx => verify-recipient-address.mdx} | 56 ++- .../payments/{interop => }/wrap-unwrap.mdx | 52 ++- light-token/wallets/gasless-transactions.mdx | 187 +++++++++- light-token/wallets/overview.mdx | 2 + light-token/wallets/smart-wallets.mdx | 340 ++++++++++++++++++ light-token/welcome.mdx | 2 - scripts/copy-payments-snippets.sh | 77 ++++ snippets/ai-prompts/wallets/smart-wallets.mdx | 159 ++++++++ .../payments/interop/register-spl-mint.mdx | 46 +++ .../code-snippets/payments/interop/unwrap.mdx | 68 ++++ .../code-snippets/payments/interop/wrap.mdx | 75 ++++ .../payments/receive/receive.mdx | 53 +++ .../payments/send/batch-send.mdx | 75 ++++ .../payments/send/payment-with-memo.mdx | 71 ++++ .../payments/send/send-action.mdx | 32 ++ .../payments/send/send-instruction.mdx | 40 +++ .../payments/send/sign-all-transactions.mdx | 70 ++++ .../spend-permissions/delegate-approve.mdx | 25 ++ .../spend-permissions/delegate-check.mdx | 60 ++++ .../spend-permissions/delegate-full-flow.mdx | 65 ++++ .../spend-permissions/delegate-revoke.mdx | 31 ++ .../payments/verify/get-balance.mdx | 41 +++ .../payments/verify/get-history.mdx | 33 ++ .../payments/verify/verify-address.mdx | 61 ++++ 39 files changed, 2254 insertions(+), 592 deletions(-) delete mode 100644 light-token/payments/advanced/deferred-execution.mdx rename light-token/payments/{send-payments => }/basic-payment.mdx (68%) create mode 100644 light-token/payments/batch-payments.mdx rename light-token/payments/{send-payments => }/payment-with-memo.mdx (76%) rename light-token/payments/{accept-payments => }/receive-payments.mdx (74%) delete mode 100644 light-token/payments/send-payments/batch-payments.mdx delete mode 100644 light-token/payments/send-payments/fee-abstraction.mdx rename light-token/payments/{advanced => }/spend-permissions.mdx (55%) rename light-token/payments/{accept-payments => }/verify-payments.mdx (64%) rename light-token/payments/{send-payments/verify-address.mdx => verify-recipient-address.mdx} (71%) rename light-token/payments/{interop => }/wrap-unwrap.mdx (81%) create mode 100644 light-token/wallets/smart-wallets.mdx create mode 100755 scripts/copy-payments-snippets.sh create mode 100644 snippets/ai-prompts/wallets/smart-wallets.mdx create mode 100644 snippets/code-snippets/payments/interop/register-spl-mint.mdx create mode 100644 snippets/code-snippets/payments/interop/unwrap.mdx create mode 100644 snippets/code-snippets/payments/interop/wrap.mdx create mode 100644 snippets/code-snippets/payments/receive/receive.mdx create mode 100644 snippets/code-snippets/payments/send/batch-send.mdx create mode 100644 snippets/code-snippets/payments/send/payment-with-memo.mdx create mode 100644 snippets/code-snippets/payments/send/send-action.mdx create mode 100644 snippets/code-snippets/payments/send/send-instruction.mdx create mode 100644 snippets/code-snippets/payments/send/sign-all-transactions.mdx create mode 100644 snippets/code-snippets/payments/spend-permissions/delegate-approve.mdx create mode 100644 snippets/code-snippets/payments/spend-permissions/delegate-check.mdx create mode 100644 snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx create mode 100644 snippets/code-snippets/payments/spend-permissions/delegate-revoke.mdx create mode 100644 snippets/code-snippets/payments/verify/get-balance.mdx create mode 100644 snippets/code-snippets/payments/verify/get-history.mdx create mode 100644 snippets/code-snippets/payments/verify/verify-address.mdx diff --git a/docs.json b/docs.json index 0b6f53f..6c61979 100644 --- a/docs.json +++ b/docs.json @@ -57,31 +57,24 @@ "group": "For Stablecoin Payments", "pages": [ "light-token/payments/overview", - "light-token/payments/integration-guide", { "group": "Send Payments", "pages": [ - "light-token/payments/send-payments/basic-payment", - "light-token/payments/send-payments/payment-with-memo", - "light-token/payments/send-payments/verify-address", - "light-token/payments/send-payments/batch-payments", - "light-token/payments/send-payments/fee-abstraction" + "light-token/payments/basic-payment", + "light-token/payments/batch-payments", + "light-token/payments/payment-with-memo" ] }, + "light-token/payments/receive-payments", { - "group": "Accept Payments", + "group": "Verify Payments", "pages": [ - "light-token/payments/accept-payments/receive-payments", - "light-token/payments/accept-payments/verify-payments" + "light-token/payments/verify-payments", + "light-token/payments/verify-recipient-address" ] }, - { - "group": "Advanced", - "pages": [ - "light-token/payments/advanced/deferred-execution" - ] - }, - "light-token/payments/interop/wrap-unwrap", + "light-token/payments/spend-permissions", + "light-token/payments/wrap-unwrap", "light-token/payments/production-readiness" ] }, @@ -91,7 +84,8 @@ "light-token/wallets/overview", "light-token/wallets/privy", "light-token/wallets/wallet-adapter", - "light-token/wallets/gasless-transactions" + "light-token/wallets/gasless-transactions", + "light-token/wallets/smart-wallets" ] }, { @@ -966,6 +960,10 @@ "source": "/light-token/wallets/sponsor-top-ups", "destination": "https://zkcompression.com/light-token/wallets/gasless-transactions" }, + { + "source": "/light-token/payments/fee-abstraction", + "destination": "https://zkcompression.com/light-token/wallets/gasless-transactions" + }, { "source": "/light-token/toolkits/for-streaming-mints", "destination": "https://zkcompression.com/light-token/streaming/mints" diff --git a/light-token/defi/programs-pinocchio.mdx b/light-token/defi/programs-pinocchio.mdx index f7689b4..f22b88f 100644 --- a/light-token/defi/programs-pinocchio.mdx +++ b/light-token/defi/programs-pinocchio.mdx @@ -521,7 +521,5 @@ depending on number and type of accounts being initialized or loaded. --- -API is in Beta and subject to change. - Questions or need hands-on support? [Telegram](https://t.me/swen_light) | [email](mailto:support@lightprotocol.com) | [Discord](https://discord.com/invite/7cJ8BhAXhu) diff --git a/light-token/defi/programs.mdx b/light-token/defi/programs.mdx index 3d1d6bd..a807d87 100644 --- a/light-token/defi/programs.mdx +++ b/light-token/defi/programs.mdx @@ -552,7 +552,5 @@ depending on number and type of accounts being initialized or loaded. --- -API is in Beta and subject to change. - Questions or need hands-on support? [Telegram](https://t.me/swen_light) | [email](mailto:support@lightprotocol.com) | [Discord](https://discord.com/invite/7cJ8BhAXhu) diff --git a/light-token/defi/routers.mdx b/light-token/defi/routers.mdx index 07ed690..cdb7ca0 100644 --- a/light-token/defi/routers.mdx +++ b/light-token/defi/routers.mdx @@ -309,8 +309,6 @@ but requires no streaming setup. --- -API is in Beta and subject to change. - Questions or need hands-on support? [Telegram](https://t.me/swen_light) | [email](mailto:support@lightprotocol.com) | [Discord](https://discord.com/invite/7cJ8BhAXhu) diff --git a/light-token/payments/advanced/deferred-execution.mdx b/light-token/payments/advanced/deferred-execution.mdx deleted file mode 100644 index 339f80e..0000000 --- a/light-token/payments/advanced/deferred-execution.mdx +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Deferred Execution" -sidebarTitle: "Deferred execution" -description: "Sign transactions now and execute later using durable nonces, with considerations for Light Token's cold account lifecycle." -keywords: ["deferred execution solana", "durable nonce solana", "sign now execute later", "treasury operations solana"] ---- - -import SupportFooter from "/snippets/support-footer.mdx"; - -Durable nonces let you sign a transaction now and execute it later. -This is useful for treasury operations, multi-party approval workflows, -and scheduled payments. - -## How durable nonces work - -Standard Solana transactions expire after ~90 seconds (the blockhash lifetime). -Durable nonces replace the blockhash with a nonce value that does not expire, -allowing the signed transaction to be stored and submitted at any future time. - -For the complete durable nonce pattern, see -[Solana's deferred execution guide](https://solana.com/docs/payments/advanced-payments/deferred-execution). - -## Cold account considerations - - -Light Token accounts can transition between hot and cold states. This adds a constraint -to deferred execution that does not exist with standard SPL tokens. - - -When you build a deferred transaction, the SDK may include load instructions for cold accounts. -If the account's state changes between signing and execution, those instructions may become stale: - -- **Hot → cold**: The account compressed after signing. The pre-signed transfer instruction - expects a hot account but finds nothing on-chain. -- **Cold → hot**: Another transaction loaded the account after signing. The pre-signed load - instructions try to load an already-hot account (may succeed as a no-op, but adds unnecessary cost). - -## When deferred execution works safely - -Deferred execution works well when: - -- **Accounts are actively used**: Regular writes keep the virtual rent balance topped up, - preventing accounts from going cold. -- **Your app controls the fee payer**: Your application server pays rent top-ups on every - interaction, keeping accounts hot. -- **Short deferral periods**: The shorter the delay between signing and execution, the less - likely account state changes. - -## When to be cautious - -Avoid deferred execution when: - -- **Accounts may go cold**: If no writes happen for ~24 hours, accounts auto-compress. - A transaction signed before compression will reference stale state. -- **Long deferral periods**: Treasury operations that sit for days or weeks risk account - state changes. -- **Unknown account activity**: If you cannot predict whether the accounts will remain - active, deferred execution is unreliable. - -## Alternative patterns - -For use cases that need delayed execution with Light Token: - -- **Scheduled execution**: Build and submit the transaction at execution time rather than - pre-signing. This ensures load instructions reflect current account state. - -## Related guides - - - - Separate the fee payer from the token owner. - - - Checklist for deploying Light Token in production. - - - - diff --git a/light-token/payments/send-payments/basic-payment.mdx b/light-token/payments/basic-payment.mdx similarity index 68% rename from light-token/payments/send-payments/basic-payment.mdx rename to light-token/payments/basic-payment.mdx index 0fd8f4b..4d5a0e0 100644 --- a/light-token/payments/send-payments/basic-payment.mdx +++ b/light-token/payments/basic-payment.mdx @@ -1,46 +1,77 @@ --- title: "Basic Payment" -sidebarTitle: "Basic payment" -description: "Send a single token transfer with Light Token." +sidebarTitle: "Basic Payment" +description: "Send a single token transfer with Light Token APIs for stablecoin payments with comparison to SPL." keywords: ["stablecoin transfer solana", "light token transfer", "send payment solana", "rent free transfer"] --- import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; +import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; + +1. The light-token API matches the SPL-token API almost entirely, and extends their functionality to include the light token program in addition to the SPL-token and Token-2022 programs. +2. Your users use the same stablecoins, just stored more efficiently. + + + + + + + + + + + + + + + + +
SPLLight
**Transfer**createTransferInstruction()createTransferInterfaceInstructions()
+ + -Send a single token transfer between two wallets. The Light Token transfer API mirrors SPL but handles -cold account loading and associated token account creation automatically. - - -Find full runnable code examples: -[instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/send-instruction.ts) | -[action](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/send-action.ts). - - -## How it works - -1. The SDK checks whether the sender's account has a cold balance and adds load instructions if needed. -2. If the recipient does not have a Light Token associated token account, the SDK creates one. -3. The transfer executes atomically. - -APIs return `TransactionInstruction[][]` — an array of transaction batches. Almost always a single -transaction, but the loop pattern handles the rare multi-transaction case automatically. + + ## Setup Snippets below assume `rpc`, `payer`, `mint`, `owner`, `recipient`, and `amount` are defined. -See the [full examples](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets) for runnable setup. +See the [full examples](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments) for runnable setup. ```typescript import { createRpc } from "@lightprotocol/stateless.js"; +import { + createTransferInterfaceInstructions, + transferInterface +} from "@lightprotocol/compressed-token/unified"; + const rpc = createRpc(RPC_ENDPOINT); ``` + +Find full runnable code examples: +[instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send-instruction.ts) | +[action](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send-action.ts). + + ## Send a payment + +The SDK checks whether the sender's account has a cold balance and adds load instructions if needed. + + +**About loading**: Light Token accounts reduce account rent ~200x by auto-compressing inactive +accounts. Before any action, the SDK detects cold balances and adds +instructions to load them. This almost always fits in a single +atomic transaction with your regular transfer. APIs return `TransactionInstruction[][]` so the same +loop handles the rare multi-transaction case automatically. + + @@ -66,10 +97,33 @@ for (const ixs of instructions) { } ``` - + + + +```typescript +import { + getAssociatedTokenAddressSync, + createAssociatedTokenAccountIdempotentInstruction, + createTransferInstruction, +} from "@solana/spl-token"; + +const sourceAta = getAssociatedTokenAddressSync(mint, owner.publicKey); +const destinationAta = getAssociatedTokenAddressSync(mint, recipient); + +const tx = new Transaction().add( + createAssociatedTokenAccountIdempotentInstruction( + payer.publicKey, destinationAta, recipient, mint + ), + createTransferInstruction(sourceAta, destinationAta, owner.publicKey, amount) +); +``` + + Your app logic may require you to create a single sign request for your user: + + ```typescript const transactions = instructions.map((ixs) => new Transaction().add(...ixs)); @@ -83,13 +137,13 @@ for (const tx of signed) { - - While almost always you will have only one transfer transaction, you can optimize sending in the rare cases where you have multiple transactions. Parallelize the loads, confirm them, and then send the transfer instruction after. + + ```typescript import { createTransferInterfaceInstructions, @@ -121,28 +175,6 @@ await sendAndConfirmTransaction(rpc, transferTx); - - -```typescript -import { - getAssociatedTokenAddressSync, - createAssociatedTokenAccountIdempotentInstruction, - createTransferInstruction, -} from "@solana/spl-token"; - -const sourceAta = getAssociatedTokenAddressSync(mint, owner.publicKey); -const destinationAta = getAssociatedTokenAddressSync(mint, recipient); - -const tx = new Transaction().add( - createAssociatedTokenAccountIdempotentInstruction( - payer.publicKey, destinationAta, recipient, mint - ), - createTransferInstruction(sourceAta, destinationAta, owner.publicKey, amount) -); -``` - - - @@ -179,17 +211,23 @@ await transfer(connection, payer, sourceAta, destinationAta, owner, amount); + + + + + + ## Related guides - - Handle multi-transaction batches and multiple recipients. + + Pack multiple transfers to multiple recipients into one transaction. - - Separate the fee payer from the token owner. + + Abstract SOL fees from the user. Sponsor top-ups and transaction fees. - - Load cold accounts and prepare to receive. + + Unify token balances and share ATA address with the sender. diff --git a/light-token/payments/batch-payments.mdx b/light-token/payments/batch-payments.mdx new file mode 100644 index 0000000..b5dcbb1 --- /dev/null +++ b/light-token/payments/batch-payments.mdx @@ -0,0 +1,220 @@ +--- +title: "Batch Payments" +sidebarTitle: "Batch Payments" +description: "Send payments to multiple recipients in a single transaction or sequentially." +keywords: ["batch payments solana", "multiple transfers solana", "light token batch", "multi-recipient transfer"] +--- + +import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; +import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; + +Send payments to multiple recipients in a single atomic transaction. + + + + + + + + + + + + + + + + +
SPLLight
**Transfer**createTransferInstruction()createTransferInterfaceInstructions()
+ + + + + + +## Setup + + + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; + +const rpc = createRpc(RPC_ENDPOINT); +``` + + +Find full code examples: +[single transaction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/batch-send-single-tx.ts) | +[sequential](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/batch-send.ts). + + +## Send to multiple recipients in one transaction + +Load all accounts first, then batch the transfers into a single atomic transaction. + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { + createLoadAtaInstructions, + createTransferInterfaceInstructions, + getAssociatedTokenAddressInterface, +} from "@lightprotocol/compressed-token/unified"; + +const recipients = [ + { address: recipient1, amount: 100 }, + { address: recipient2, amount: 200 }, + { address: recipient3, amount: 300 }, +]; + +// 1. Load sender's cold balance (if needed) +const senderAta = getAssociatedTokenAddressInterface(mint, owner.publicKey); +const loadSenderIxs = await createLoadAtaInstructions( + rpc, senderAta, owner.publicKey, mint, payer.publicKey +); +for (const ixs of loadSenderIxs) { + await sendAndConfirmTransaction(rpc, new Transaction().add(...ixs), [payer]); +} + +// 2. Load/create each recipient's associated token account +for (const { address } of recipients) { + const recipientAta = getAssociatedTokenAddressInterface(mint, address); + const loadIxs = await createLoadAtaInstructions( + rpc, recipientAta, address, mint, payer.publicKey + ); + for (const ixs of loadIxs) { + await sendAndConfirmTransaction(rpc, new Transaction().add(...ixs), [payer]); + } +} + +// 3. All accounts are hot — batch transfers in one transaction +const COMPUTE_BUDGET_ID = "ComputeBudget111111111111111111111111111111"; +const allTransferIxs = []; +let isFirst = true; + +for (const { address, amount } of recipients) { + const ixs = await createTransferInterfaceInstructions( + rpc, payer.publicKey, mint, amount, owner.publicKey, address + ); + // Filter duplicate ComputeBudget instructions from subsequent calls + for (const ix of ixs[0]) { + if (!isFirst && ix.programId.toBase58() === COMPUTE_BUDGET_ID) continue; + allTransferIxs.push(ix); + } + isFirst = false; +} + +const batchTx = new Transaction().add(...allTransferIxs); +await sendAndConfirmTransaction(rpc, batchTx, [payer, owner]); +``` + +## Send to multiple recipients sequentially + +When you cannot pre-load accounts or want simpler code, process each recipient independently. +Cold accounts are loaded automatically. + +```typescript +const recipients = [ + { address: recipientA, amount: 100 }, + { address: recipientB, amount: 200 }, + { address: recipientC, amount: 300 }, +]; + +for (const { address, amount } of recipients) { + const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + address + ); + + for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); + } +} +``` + +## Advanced patterns + + + +Every Light Token API that modifies state returns `TransactionInstruction[][]`. +Each inner array is one atomic transaction. Almost always a single transaction, +but the loop pattern handles the rare multi-transaction case (cold account loading) automatically. + +```typescript +const instructions = await createTransferInterfaceInstructions( + rpc, payer.publicKey, mint, amount, owner.publicKey, recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + + +When the SDK returns multiple transaction batches (load + transfer), parallelize +the loads and send the transfer last. + +```typescript +import { sliceLast } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, payer.publicKey, mint, amount, owner.publicKey, recipient +); + +const { rest: loadInstructions, last: transferInstructions } = sliceLast(instructions); + +await Promise.all( + loadInstructions.map(async (ixs) => { + const tx = new Transaction().add(...ixs); + return sendAndConfirmTransaction(rpc, tx, [payer, owner]); + }) +); + +const transferTx = new Transaction().add(...transferInstructions); +await sendAndConfirmTransaction(rpc, transferTx, [payer, owner]); +``` + + + + + +For wallet integrations (Privy, Wallet Adapter), use a helper that handles +blockhash, signing, sending, and confirming for each batch. + +See the complete implementation in the +[Privy integration](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/sign-with-privy/react/src/hooks/signAndSendBatches.ts) and +[Wallet Adapter integration](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter) examples. + + + + + + + + + +## Related guides + + + + Send a single transfer. + + + Separate the fee payer from the token owner. + + + Load cold accounts and share ATA address with the sender. + + + + \ No newline at end of file diff --git a/light-token/payments/overview.mdx b/light-token/payments/overview.mdx index 30eee2a..df89cbe 100644 --- a/light-token/payments/overview.mdx +++ b/light-token/payments/overview.mdx @@ -67,7 +67,7 @@ For example, here is the creation of an associated token account: Token extensions introduce optional features you can add to a token mint or token account through extra instructions. - + | Extension | Description | |-----------|-------------| @@ -95,44 +95,27 @@ Learn more on extensions here: [Extensions](https://solana.com/docs/tokens/exten ## Start Integrating - - - - -## Payment guides - +### Payment Flows - - Single token transfer with Light Token. - - - Load cold accounts and share your address. - - - Separate the fee payer from the token owner. - - - Checklist for deploying to production. - + + + + + + + + + +### Gasless Transactions + + +### Signing + + + +### Go to Production + diff --git a/light-token/payments/send-payments/payment-with-memo.mdx b/light-token/payments/payment-with-memo.mdx similarity index 76% rename from light-token/payments/send-payments/payment-with-memo.mdx rename to light-token/payments/payment-with-memo.mdx index 526cde8..7bfe810 100644 --- a/light-token/payments/send-payments/payment-with-memo.mdx +++ b/light-token/payments/payment-with-memo.mdx @@ -1,21 +1,40 @@ --- title: "Payment with Memo" -sidebarTitle: "Payment with memo" +sidebarTitle: "Payment with Memo" description: "Attach invoice IDs, payment references, or notes to Light Token transfers using the memo program." keywords: ["memo payment solana", "invoice reconciliation solana", "payment reference light token", "memo instruction"] --- import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; +import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; Attach metadata like invoice IDs or payment references to a Light Token transfer using Solana's memo program. The memo is recorded in the transaction logs for reconciliation. - -The memo program is a standard Solana program that works with any transaction. -Adding a memo instruction alongside a Light Token transfer should work, but verify -on devnet before using in production. - + + + + + + + + + + + + + + + +
SPLLight
**Transfer**createTransferInstruction()createTransferInterfaceInstructions()
+ + + + + + ## How it works @@ -95,15 +114,24 @@ const memoLogs = logs.filter((log) => console.log("Memo logs:", memoLogs); ``` + + + + + + ## Related guides - - + + Send a single transfer without memo. - + Query balances and transaction history. + + Pack multiple transfers into one transaction. + - + \ No newline at end of file diff --git a/light-token/payments/production-readiness.mdx b/light-token/payments/production-readiness.mdx index 9cdddb8..d1174af 100644 --- a/light-token/payments/production-readiness.mdx +++ b/light-token/payments/production-readiness.mdx @@ -1,21 +1,18 @@ --- title: "Production Readiness" -sidebarTitle: "Production readiness" -description: "Checklist for deploying Light Token payment flows to production, including RPC infrastructure, error handling, and security." +sidebarTitle: "Production Readiness" +description: "Non-exhaustive checklist for deploying Light Token payment flows to production, including RPC infrastructure, error handling, and security." keywords: ["production readiness solana", "light token production", "photon indexer", "mainnet deployment solana"] --- import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; +import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; -Checklist and considerations for deploying Light Token payment flows to production. + -## Current status - - -Light Token is in **Beta on Solana devnet**. Mainnet launch is expected in Q1 2026. -For production use today, use [Compressed Tokens V1](/resources/legacy-compressed-tokens), -which are live on Solana mainnet and supported by Phantom and Backpack. - + + ## RPC infrastructure @@ -39,18 +36,23 @@ For production reliability, configure multiple RPC endpoints: ```typescript import { createRpc } from "@lightprotocol/stateless.js"; -// Primary endpoint -const rpc = createRpc(process.env.PRIMARY_RPC_URL); - -// Fallback: switch to secondary if primary fails +const primaryRpc = createRpc(process.env.PRIMARY_RPC_URL); const fallbackRpc = createRpc(process.env.SECONDARY_RPC_URL); + +async function sendWithFallback(fn: (rpc: any) => Promise) { + try { + return await fn(primaryRpc); + } catch { + return await fn(fallbackRpc); + } +} ``` ## Transaction landing Light Token transactions follow standard Solana patterns for landing: -- **Priority fees**: Use `ComputeBudgetProgram.setComputeUnitPrice()` to increase transaction priority. +- **Priority fees**: Use `ComputeBudgetProgram.setComputeUnitPrice()` to increase transaction priority. See [Solana priority fees](https://solana.com/docs/core/fees). - **Compute units**: Set appropriate compute unit limits with `ComputeBudgetProgram.setComputeUnitLimit()`. - **Retry logic**: Implement retries with fresh blockhashes for failed transactions. @@ -66,24 +68,23 @@ Light Token transactions follow standard Solana patterns for landing: Handle both standard Solana errors and Light Token-specific scenarios: -- **Cold account load failures**: Retry the load if the indexer returns stale data. +- **[Cold account](/light-token/payments/receive-payments) load failures**: Retry the load if the indexer returns stale data. - **Associated token account creation**: Idempotent — safe to retry. -- **Rent top-up failures**: Ensure the fee payer has sufficient SOL balance. -- **Transaction size limits**: If `TransactionInstruction[][]` returns multiple batches, process them sequentially. +- **Rent top-up failures**: Ensure the fee payer has sufficient SOL balance. See [gasless transactions](/light-token/wallets/gasless-transactions) for cost breakdown. +- **Transaction size limits**: If `TransactionInstruction[][]` returns [multiple batches](/light-token/payments/basic-payment), process them sequentially. ## Fee sponsorship Set your application as the fee payer so users never interact with SOL: -1. **Rent top-ups**: Set `payer` parameter on Light Token instructions. See [fee abstraction](/light-token/payments/send-payments/fee-abstraction). -2. **Transaction fees**: Use standard Solana fee payer patterns or services like [Kora](https://github.com/nicholasgasior/kora). -3. **Rent sponsor funding**: Ensure the rent sponsor PDA is funded. See [gasless transactions](/light-token/wallets/gasless-transactions). +1. **Rent top-ups and transaction fees**: Set `payer` parameter on Light Token instructions. See [gasless transactions](/light-token/wallets/gasless-transactions). +2. **Rent sponsor funding**: Ensure the rent sponsor PDA is funded. See the [cost breakdown](/light-token/wallets/gasless-transactions) for required amounts. ## Security - **Key management**: Use hardware security modules (HSMs) or managed key services for production signing keys. - **Signing infrastructure**: Separate hot wallets (for automated operations) from cold wallets (for treasury). -- **Address verification**: Validate recipient addresses before sending. See [verify address](/light-token/payments/send-payments/verify-address). +- **Address verification**: Validate recipient addresses before sending. See [verify address](/light-token/payments/verify-recipient-address). - **Monitoring**: Track transaction success rates, cold account loading frequency, and fee payer SOL balance. ## Pre-launch checklist @@ -91,26 +92,32 @@ Set your application as the fee payer so users never interact with SOL: - [ ] Photon-compatible RPC endpoint configured and tested - [ ] Redundant RPC endpoint available for failover - [ ] Fee payer wallet funded with sufficient SOL -- [ ] Cold account loading tested end-to-end +- [ ] [Cold account loading](/light-token/payments/receive-payments) tested end-to-end - [ ] Error handling covers load failures, tx size limits, and retries - [ ] Confirmation level appropriate for your use case -- [ ] Address verification implemented -- [ ] Monitoring and alerting set up -- [ ] Wrap/unwrap flows tested for CEX interoperability (if applicable) -- [ ] Wrap/unwrap flows tested for SPL interoperability +- [ ] [Address verification](/light-token/payments/verify-recipient-address) implemented +- [ ] Monitoring and alerting set up (tx success rates, cold account loading, fee payer balance) +- [ ] [Wrap/unwrap](/light-token/payments/wrap-unwrap) flows tested for CEX interoperability (if applicable) +- [ ] [Wrap/unwrap](/light-token/payments/wrap-unwrap) flows tested for SPL interoperability (if applicable) + + + + + + ## Related guides - + Abstract fees for users. - + Send a single transfer. - + Load cold accounts and prepare to receive. - + \ No newline at end of file diff --git a/light-token/payments/accept-payments/receive-payments.mdx b/light-token/payments/receive-payments.mdx similarity index 74% rename from light-token/payments/accept-payments/receive-payments.mdx rename to light-token/payments/receive-payments.mdx index 6584f5d..36530da 100644 --- a/light-token/payments/accept-payments/receive-payments.mdx +++ b/light-token/payments/receive-payments.mdx @@ -1,19 +1,40 @@ --- title: "Receive Payments" -sidebarTitle: "Receive payments" +sidebarTitle: "Receive Payments" description: "Prepare to receive token payments by loading cold accounts and sharing your associated token account address." keywords: ["receive stablecoin solana", "light token receive", "load ata solana", "cold account loading"] --- import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; +import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; +1. Share the associated token account address with the sender. +2. We recommend to prepend a load instruction before. Load creates the associated token account if needed and loads any cold balance into it. -Share the associated token account address with the sender. - -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/receive.ts). - + + + + + + + + + + + + + + + +
SPLLight
**Receive**getOrCreateAssociatedTokenAccount()createLoadAtaInstructions()
+ + + + + **About loading**: Light Token accounts reduce account rent ~200x by auto-compressing inactive @@ -44,6 +65,9 @@ const ata = getAssociatedTokenAddressInterface(mint, recipient); ``` ## Load the associated token account + +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/receive.ts). + @@ -92,11 +116,6 @@ if (sig) console.log("Loaded:", sig); - -The `payer` on load instructions is the fee sponsor. Set your application as the payer so users never interact with SOL. -See [fee abstraction](/light-token/payments/send-payments/fee-abstraction) for details. - - ```typescript @@ -121,15 +140,24 @@ const ata = await getOrCreateAssociatedTokenAccount( + + + + + + ## Related guides - - + + Check balances and transaction history. - + Abstract SOL fees so users never hold SOL. + + Send a single token transfer. + - + \ No newline at end of file diff --git a/light-token/payments/send-payments/batch-payments.mdx b/light-token/payments/send-payments/batch-payments.mdx deleted file mode 100644 index cb50eb7..0000000 --- a/light-token/payments/send-payments/batch-payments.mdx +++ /dev/null @@ -1,179 +0,0 @@ ---- -title: "Batch Payments" -sidebarTitle: "Batch payments" -description: "Handle multi-transaction batches and send payments to multiple recipients." -keywords: ["batch payments solana", "multiple transfers solana", "light token batch", "signAndSendBatches"] ---- - -import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; - -Handle the `TransactionInstruction[][]` pattern that Light Token APIs return, -and send payments to multiple recipients. - - -**How Light Token batching differs from SPL**: SPL batching puts multiple transfer instructions -in a single transaction. Light Token APIs return `TransactionInstruction[][]` because -cold accounts may need loading before the transfer can execute. Each inner array is one -atomic transaction. Almost always a single transaction, but the pattern handles multi-transaction -cases automatically. - - -## Setup - - - -```typescript -import { createRpc } from "@lightprotocol/stateless.js"; - -const rpc = createRpc(RPC_ENDPOINT); -``` - -## Handle instruction batches - -Every Light Token API that modifies state returns `TransactionInstruction[][]`. -The standard loop handles all cases: - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, - payer.publicKey, - mint, - amount, - owner.publicKey, - recipient -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); -} -``` - -## Parallelize load transactions - -When the SDK returns multiple transaction batches (load + transfer), you can -parallelize the load transactions and send the transfer last: - -```typescript -import { - createTransferInterfaceInstructions, - sliceLast, -} from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, - payer.publicKey, - mint, - amount, - owner.publicKey, - recipient -); - -const { rest: loadInstructions, last: transferInstructions } = sliceLast(instructions); - -// Parallelize loads (empty = nothing to load, will no-op) -await Promise.all( - loadInstructions.map((ixs) => { - const tx = new Transaction().add(...ixs); - tx.sign(payer, owner); - return sendAndConfirmTransaction(rpc, tx); - }) -); - -// Send transfer after all loads confirm -const transferTx = new Transaction().add(...transferInstructions); -transferTx.sign(payer, owner); -await sendAndConfirmTransaction(rpc, transferTx); -``` - -## Helper: signAndSendBatches - -For wallet integrations (Privy, Wallet Adapter), use a shared helper -that handles blockhash, signing, sending, and confirming for each batch: - -```typescript -import { Transaction, TransactionInstruction, PublicKey } from "@solana/web3.js"; - -async function signAndSendBatches( - instructionBatches: TransactionInstruction[][], - rpc: any, - feePayer: PublicKey, - signTransaction: (tx: Transaction) => Promise -): Promise { - const signatures: string[] = []; - - for (const ixs of instructionBatches) { - const tx = new Transaction().add(...ixs); - const { blockhash } = await rpc.getLatestBlockhash(); - tx.recentBlockhash = blockhash; - tx.feePayer = feePayer; - - const signedTx = await signTransaction(tx); - const sig = await rpc.sendRawTransaction(signedTx.serialize(), { - skipPreflight: false, - preflightCommitment: "confirmed", - }); - await rpc.confirmTransaction(sig, "confirmed"); - signatures.push(sig); - } - - return signatures.length > 0 ? signatures[signatures.length - 1] : null; -} -``` - - -See the complete implementation in the -[Privy integration](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/sign-with-privy/react/src/hooks/signAndSendBatches.ts) and -[Wallet Adapter integration](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter) examples. - - -## Send to multiple recipients - -Call `createTransferInterfaceInstructions()` per recipient and process sequentially: - -```typescript -const recipients = [ - { address: recipientA, amount: 100 }, - { address: recipientB, amount: 200 }, - { address: recipientC, amount: 300 }, -]; - -for (const { address, amount } of recipients) { - const instructions = await createTransferInterfaceInstructions( - rpc, - payer.publicKey, - mint, - amount, - owner.publicKey, - address - ); - - for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); - } -} -``` - - -When all accounts are hot (no loading needed), multiple transfer instructions can fit in a single -Solana transaction. However, the SDK does not batch multi-recipient transfers natively — call -`createTransferInterfaceInstructions()` per recipient. - - -## Related guides - - - - Send a single transfer. - - - Separate the fee payer from the token owner. - - - - diff --git a/light-token/payments/send-payments/fee-abstraction.mdx b/light-token/payments/send-payments/fee-abstraction.mdx deleted file mode 100644 index 60bc7d5..0000000 --- a/light-token/payments/send-payments/fee-abstraction.mdx +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: "Fee Abstraction" -sidebarTitle: "Fee abstraction" -description: "Abstract fees so users never interact with SOL. Separate the fee payer from the token owner." -keywords: ["fee abstraction solana", "gasless transfer solana", "rent sponsorship light token", "sponsor rent solana"] ---- - -import RentSponsorship from "/snippets/rent-sponsorship-explained.mdx"; -import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; - -Light Token provides built-in rent sponsorship. Set a separate `payer` from the `authority` so your -application covers rent top-ups while users only sign to authorize their transfers. - - -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/gasless-transactions/typescript/gasless-transfer.ts). - - -## How fee sponsorship works - -Light Token transfers accept two distinct roles: - -| Role | Parameter | What it does | -|:-----|:----------|:-------------| -| **Payer** (fee payer) | First positional arg | Pays rent top-ups to keep accounts active. Can be your application server. | -| **Authority** (owner) | `owner` / authority arg | Signs to authorize the token transfer. The account holder. | - -When payer and authority are different, both must sign the transaction. - -## Rent sponsorship - - - -## Setup - - - -```typescript -import { createRpc } from "@lightprotocol/stateless.js"; - -const rpc = createRpc(RPC_ENDPOINT); -``` - -## Send with a separate fee payer - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -// Sponsor covers rent top-ups, sender authorizes the transfer. -const instructions = await createTransferInterfaceInstructions( - rpc, - sponsor.publicKey, // payer: covers rent top-ups - mint, - amount, - sender.publicKey, // authority: user signs to authorize - recipient.publicKey -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - // Both sponsor and sender must sign - await sendAndConfirmTransaction(rpc, tx, [sponsor, sender]); -} -``` - - -This covers **rent fee abstraction** — your app pays the small rent top-ups (766 lamports by default per write). -For **transaction fee abstraction** (paying the Solana base fee on behalf of users), see [Solana's fee abstraction patterns](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction). - - - - -Solana's standard fee abstraction uses [Kora](https://github.com/nicholasgasior/kora) to sponsor transaction fees. -Light Token handles rent natively — the `payer` parameter on any Light Token instruction determines who pays rent top-ups. -No external service is needed for rent sponsorship. - -For a complete fee-free user experience, combine both: -1. Light Token's `payer` parameter for rent top-ups -2. Standard Solana fee payer for transaction base fees - - - -## Related guides - - - - Detailed setup guide for wallet-based rent sponsorship. - - - Send a single token transfer. - - - - diff --git a/light-token/payments/advanced/spend-permissions.mdx b/light-token/payments/spend-permissions.mdx similarity index 55% rename from light-token/payments/advanced/spend-permissions.mdx rename to light-token/payments/spend-permissions.mdx index 9e3c63b..631951b 100644 --- a/light-token/payments/advanced/spend-permissions.mdx +++ b/light-token/payments/spend-permissions.mdx @@ -1,17 +1,46 @@ --- title: "Spend Permissions" -sidebarTitle: "Spend permissions" +sidebarTitle: "Spend Permissions" description: "Delegate token spending to third parties with amount caps for subscriptions, recurring payments, and managed spending." keywords: ["delegate tokens solana", "token delegation light token", "spend permissions solana", "recurring payments solana"] --- import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; +import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; Delegate token spending to a third party with an amount cap. The delegate can transfer tokens on behalf of the owner up to the approved amount, without the owner signing each transaction. + + + + + + + + + + + + + + + + + + + + +
SPLLight
**Approve**approve()approveInterface()
**Revoke**revoke()revokeInterface()
+ + + + + + ## Use cases | Use case | How delegation helps | @@ -36,31 +65,32 @@ const rpc = createRpc(RPC_ENDPOINT); Grant a delegate permission to spend up to a capped amount: ```typescript -import { approve } from "@lightprotocol/compressed-token"; +import { approveInterface } from "@lightprotocol/compressed-token/unified"; -const tx = await approve( +const tx = await approveInterface( rpc, payer, + senderAta, mint, - 500, // amount cap - owner, // token owner (signs) - delegate.publicKey // who gets permission + delegate.publicKey, // who gets permission + 500_000, // amount cap + owner // token owner (signs) ); console.log("Approved:", tx); ``` -## Query delegated accounts +## Check delegation status -Check which accounts a delegate has permission to spend: +Check the delegation status of an account: ```typescript -const delegatedAccounts = await rpc.getCompressedTokenAccountsByDelegate( - delegate.publicKey, - { mint } -); +import { getAtaInterface } from "@lightprotocol/compressed-token"; + +const account = await getAtaInterface(rpc, senderAta, owner.publicKey, mint); -console.log("Delegated accounts:", delegatedAccounts.items.length); +console.log("Delegate:", account.parsed.delegate?.toBase58() ?? "none"); +console.log("Delegated amount:", account.parsed.delegatedAmount.toString()); ``` ## Revoke a delegate @@ -68,19 +98,9 @@ console.log("Delegated accounts:", delegatedAccounts.items.length); Remove spending permission: ```typescript -import { revoke } from "@lightprotocol/compressed-token"; - -const delegatedAccounts = await rpc.getCompressedTokenAccountsByDelegate( - delegate.publicKey, - { mint } -); +import { revokeInterface } from "@lightprotocol/compressed-token/unified"; -const tx = await revoke( - rpc, - payer, - delegatedAccounts.items, - owner // owner signs to revoke -); +const tx = await revokeInterface(rpc, payer, senderAta, mint, owner); console.log("Revoked:", tx); ``` @@ -89,7 +109,7 @@ console.log("Revoked:", tx); - **Amount caps**: Always set the minimum amount needed. Delegation does not grant unlimited access. - **Single delegate**: Each compressed token account supports one active delegate at a time. -- **Monitor usage**: Query `getCompressedTokenAccountsByDelegate` regularly to track delegate activity. +- **Monitor usage**: Query `getAtaInterface` regularly to track delegate activity. - **Revoke promptly**: Remove delegation when the business relationship ends or the spending period expires. ## Delegation vs. custody @@ -106,15 +126,24 @@ For full TypeScript, Rust, and program-level examples, see the [approve and revoke cookbook page](/light-token/cookbook/approve-revoke). + + + + + + ## Related guides - - - Sign transactions now, execute later. + + + Send a single token transfer. - + Separate the fee payer from the token owner. + + Load cold accounts and share ATA address with the sender. + - + \ No newline at end of file diff --git a/light-token/payments/accept-payments/verify-payments.mdx b/light-token/payments/verify-payments.mdx similarity index 64% rename from light-token/payments/accept-payments/verify-payments.mdx rename to light-token/payments/verify-payments.mdx index 95781d3..4a5a2cf 100644 --- a/light-token/payments/accept-payments/verify-payments.mdx +++ b/light-token/payments/verify-payments.mdx @@ -1,14 +1,41 @@ --- title: "Verify Payments" -sidebarTitle: "Verify payments" +sidebarTitle: "Get Token Balance and Transaction History" description: "Query token balances and transaction history to verify incoming payments." keywords: ["verify payment solana", "token balance solana", "transaction history light token", "payment verification"] --- import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; - -Query balances and transaction history to confirm incoming payments. +import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; +import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; + + + + + + + + + + + + + + + + + + + + + +
SPLLight
**Get Balance**getAccount()getAtaInterface()
**Tx History**getSignaturesForAddress()rpc.getSignaturesForOwnerInterface()
+ + + + + ## Setup @@ -23,7 +50,7 @@ const rpc = createRpc(RPC_ENDPOINT); ## Query balance -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/get-balance.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/get-balance.ts). ```typescript @@ -53,7 +80,7 @@ console.log(account.amount); ## Transaction history -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/get-history.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/get-history.ts). Query all transactions for an owner across both on-chain and compressed state: @@ -76,15 +103,24 @@ const signatures = await connection.getSignaturesForAddress(ata);
+ + + + + + ## Related guides - - + + Load cold accounts and prepare to receive. - + Send a single token transfer. + + Validate recipient addresses before sending. + - + \ No newline at end of file diff --git a/light-token/payments/send-payments/verify-address.mdx b/light-token/payments/verify-recipient-address.mdx similarity index 71% rename from light-token/payments/send-payments/verify-address.mdx rename to light-token/payments/verify-recipient-address.mdx index c0e67a5..b0bd9ec 100644 --- a/light-token/payments/send-payments/verify-address.mdx +++ b/light-token/payments/verify-recipient-address.mdx @@ -1,33 +1,46 @@ --- title: "Verify Address" -sidebarTitle: "Verify address" +sidebarTitle: "Verify Recipients Address" description: "Validate recipient addresses before sending payments to prevent lost funds." keywords: ["verify address solana", "address validation light token", "solana address check", "payment safety"] --- import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; +import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; Verify recipient addresses before sending payments. Address validation prevents sending tokens to invalid or unexpected account types. + + + + + + + + + + + + + + + +
SPLLight
**Get Account**getAccount()getAtaInterface()
+ + + + + + ## Understanding Solana addresses Solana has two types of addresses: - **On-curve addresses** (wallets): derived from a keypair, can sign transactions. -- **Off-curve addresses** (PDAs): program-derived addresses, cannot sign transactions. - -## Account types in payments - -When validating a recipient, check what type of account the address belongs to: - -| Type | Description | Safe to send? | -|:-----|:------------|:--------------| -| **Wallet** | Standard keypair address, no on-chain account or a system account | Yes | -| **Light Token associated token account** | An associated token account for the target mint | Yes | -| **Token account (wrong mint)** | An associated token account for a different mint | No | -| **Program or PDA** | A program-owned account or program-derived address | Depends on use case | +- **Off-curve addresses** (PDAs): program-derived addresses, can only sign via CPI when used as [smart wallets](/light-token/wallets/smart-wallets). ## Verification flow @@ -66,15 +79,24 @@ the SDK automatically creates the recipient's associated token account if it doe Address verification is a safety check, not a prerequisite. + + + + + + ## Related guides - - + + Send a single token transfer. - + Load cold accounts and prepare to receive. + + Query balances and transaction history. + - + \ No newline at end of file diff --git a/light-token/payments/interop/wrap-unwrap.mdx b/light-token/payments/wrap-unwrap.mdx similarity index 81% rename from light-token/payments/interop/wrap-unwrap.mdx rename to light-token/payments/wrap-unwrap.mdx index 1efd9c6..1f236d5 100644 --- a/light-token/payments/interop/wrap-unwrap.mdx +++ b/light-token/payments/wrap-unwrap.mdx @@ -1,6 +1,6 @@ --- title: "Wrap and Unwrap" -sidebarTitle: "Wrap and unwrap" +sidebarTitle: "Wrap and Unwrap" description: "Move tokens between SPL / Token 2022 and Light Token accounts for CEX on-ramps, off-ramps, and interoperability." keywords: ["wrap tokens solana", "unwrap tokens solana", "spl to light token", "cex onramp solana", "token interoperability"] --- @@ -8,11 +8,40 @@ keywords: ["wrap tokens solana", "unwrap tokens solana", "spl to light token", " import RegisterSplMint from "/snippets/setup/register-spl-mint.mdx"; import ToolkitsSetup from "/snippets/setup/toolkits-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; +import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; Wrap moves tokens from an SPL or Token 2022 account into a Light Token associated token account. Unwrap moves tokens back. Use wrap/unwrap to interoperate with applications that only support SPL or Token 2022, such as centralized exchanges. + + + + + + + + + + + + + + + + + + + + +
SPLLight
**Wrap from SPL**N/AcreateWrapInstruction()
**Unwrap to SPL**N/AcreateUnwrapInstructions() / unwrap()
+ + + + + + ## When to wrap and unwrap | Flow | Use case | @@ -34,7 +63,7 @@ const rpc = createRpc(RPC_ENDPOINT); ## Wrap from SPL -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/wrap.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/wrap.ts). @@ -91,7 +120,7 @@ await wrap(rpc, payer, splAta, tokenAta, owner, mint, amount); ## Unwrap to SPL -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/unwrap.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/unwrap.ts). Unwrap moves the token balance from a Light Token associated token account to an SPL associated token account. @@ -153,15 +182,24 @@ For full TypeScript, Rust, and program-level examples, see the [wrap and unwrap cookbook page](/light-token/cookbook/wrap-unwrap). + + + + + + ## Related guides - - + + Send a single token transfer. - + Load cold accounts and prepare to receive. + + Abstract SOL fees from the user. + - + \ No newline at end of file diff --git a/light-token/wallets/gasless-transactions.mdx b/light-token/wallets/gasless-transactions.mdx index 86b4225..3e7bc73 100644 --- a/light-token/wallets/gasless-transactions.mdx +++ b/light-token/wallets/gasless-transactions.mdx @@ -1,7 +1,8 @@ --- title: Gasless Transactions -description: Abstract SOL fees so users never hold SOL. Set your application as the fee payer to sponsor rent top-ups and transaction fees. -keywords: ["gasless transactions solana", "rent sponsorship solana", "fee abstraction light token", "gasless solana tokens", "rent free tokens on solana"] +sidebarTitle: Gasless transactions +description: Abstract SOL fees so users never hold SOL. The Light SDK sponsors rent-exemption for Solana accounts and keeps accounts active through periodic top-ups paid by the fee payer. Sponsor top-ups and transaction fees by setting your application as the fee payer. +keywords: ["gasless transactions solana", "fee abstraction solana", "rent sponsorship light token", "gasless solana tokens", "rent free tokens on solana"] --- import TransferInstructionCode from "/snippets/code-snippets/light-token/gasless-transactions/ts-instruction.mdx"; @@ -12,32 +13,202 @@ import SupportFooter from "/snippets/support-footer.mdx"; --- +## Sponsor Top-ups and Transaction Fees + +Every Solana transaction requires SOL to pay network fees (around 0.001 USD) and in some cases you need to create a token account (around 0.30 USD with SPL). +Light Token lets your application cover both rent and transaction fees for around 0.001 USD. Rent sponsorship is a built-in feature of the Light SDK’s that sponsors rent-exemption for all account types to reduce creation cost. This is dealt with under the hood in a way that doesn’t disrupt the UX of what your users are used to with SPL-token. +Solana transactions have a designated fee payer, the account that pays the +network fee. By default, this is the first signer. You can specify a +different account as the fee payer, allowing a third party (the "sponsor") to +cover fees on behalf of the sender. + +Light Token extends this further. The `payer` parameter on any Light Token +instruction determines who pays rent top-ups in addition to transaction fees. +Set your application server as the payer so users never interact with SOL. -## How to sponsor rent top-ups and transaction fees +Your sponsor covers three costs: -Set the `payer` parameter to the sponsor’s public key when calling `createTransferInterfaceInstructions` (TypeScript) or building a `TransferInterface` instruction (Rust). The sponsor pays SOL for rent top-ups and transaction fees while the user only signs to authorize the transfer. +| | | | +|:-----|:-------|:----| +| **Account creation** | around 11,000 lamports (0.001 USD) | Initial bump on virtual rent balance. Rent-exemption is sponsored. | +| **Rent top-ups** | ~766 lamports per write | Fee payer bumps the virtual rent balance on each write to keep accounts active. Set `payer` parameter on any Light Token instruction. | +| **Transaction fees** | ~5,000 lamports per tx | Standard Solana fee payer. Set `feePayer` on the transaction. | - -You can set the payer to any signing account on any Light Token transaction. - +## Send a gasless transfer + + +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/gasless-transactions/typescript/gasless-transfer.ts). + + + + + + +Generate or load a keypair for the sponsor who will pay transaction fees and rent top-ups. +The sponsor needs SOL but doesn't need to hold the tokens being transferred. + +```typescript +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; + +const rpc = createRpc(RPC_ENDPOINT); + +// Sponsor: your application server +const sponsor = Keypair.fromSecretKey(/* your server keypair */); + +// User: only signs to authorize the transfer +const sender = Keypair.fromSecretKey(/* user's keypair */); +``` + + + + + +Create the transfer instruction with the sponsor as `payer` and the sender as `authority`. +The sender owns the tokens and must sign the transfer. + +```typescript +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + sponsor.publicKey, // payer: covers rent top-ups and transaction fees + mint, + amount, + sender.publicKey, // authority: user signs to authorize + recipient.publicKey +); +``` + + + + + +Both the sponsor and sender must sign the transaction: + +| | Parameter | What it does | +|:-----|:----------|:-------------| +| **Payer** (fee payer) | First positional arg | Signs to authorize payment of rent top-ups and transaction fees. Can be your application server. | +| **Authority** (owner) | `owner` / authority arg | Signs to authorize the token transfer. The account holder. | + + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + // Both sponsor and sender must sign + await sendAndConfirmTransaction(rpc, tx, [sponsor, sender]); +} +``` + + + + + + + + + + + + + +Load or generate a keypair for the sponsor. The sponsor needs SOL but doesn't need to hold the tokens being transferred. + +```rust +use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer}; + +// Sponsor: your application server +let sponsor: Keypair = /* your server keypair */; + +// User: only signs to authorize the transfer +let sender: Keypair = /* user's keypair */; +let recipient: Pubkey = /* recipient address */; +let mint: Pubkey = /* e.g. USDC mint */; +``` + + + + + +Build the transfer instruction with the sponsor as `payer` and the sender as `authority`. + +```rust +use light_token::instruction::{ + get_associated_token_address, TransferInterface, LIGHT_TOKEN_PROGRAM_ID, +}; + +let sender_ata = get_associated_token_address(&sender.pubkey(), &mint); +let recipient_ata = get_associated_token_address(&recipient, &mint); + +let transfer_ix = TransferInterface { + source: sender_ata, + destination: recipient_ata, + amount: 500_000, + decimals: 6, + authority: sender.pubkey(), // user signs to authorize + payer: sponsor.pubkey(), // sponsor covers rent top-ups and transaction fees + spl_interface: None, + source_owner: LIGHT_TOKEN_PROGRAM_ID, + destination_owner: LIGHT_TOKEN_PROGRAM_ID, +} +.instruction()?; +``` + + + + + +Both the sponsor and sender must sign the transaction. + +```rust +let sig = rpc + .create_and_send_transaction( + &[transfer_ix], + &sponsor.pubkey(), // fee payer + &[&sponsor, &sender], // both sign + ) + .await?; + +println!("Tx: {sig}"); +``` + + + + + + + + - +## Related guides + + + + Send a single token transfer. + + + Load cold accounts and prepare to receive. + + + diff --git a/light-token/wallets/overview.mdx b/light-token/wallets/overview.mdx index 2b307d9..e1d56c5 100644 --- a/light-token/wallets/overview.mdx +++ b/light-token/wallets/overview.mdx @@ -451,6 +451,8 @@ await unwrap(rpc, payer, splAta, owner, mint, amount); + + diff --git a/light-token/wallets/smart-wallets.mdx b/light-token/wallets/smart-wallets.mdx new file mode 100644 index 0000000..c604f96 --- /dev/null +++ b/light-token/wallets/smart-wallets.mdx @@ -0,0 +1,340 @@ +--- +title: "Smart Wallets" +sidebarTitle: "Using Smart Wallets" +description: "Send Light Tokens from PDA-based smart wallets. Covers off-curve associated token account creation, instruction-level transfers, and sync and async execution with Squads." +keywords: ["smart wallets solana", "squads multisig light token", "PDA wallet token transfer", "off-curve ATA solana", "rent-free tokens smart wallet"] +--- + +import SmartWalletsAiPrompt from "/snippets/ai-prompts/wallets/smart-wallets.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +--- + +A smart wallet is a program deployed on-chain that provides secure, programmable wallet infrastructure. +The signer is separate from the wallet and can be anything: passkeys, AWS KMS, MPC, or a multisig threshold. + +When a PDA owns tokens instead of a keypair, two things change: + +| | Standard wallet | Smart wallet (PDA) | +|:------|:----------------|:-------------------| +| **Create associated token account** | `createAtaInterface(rpc, payer, mint, owner)` | `createAtaInterface(rpc, payer, mint, walletPda, true)` | +| **Transfer** | `transferInterface(...)` or `createTransferInterfaceInstructions(...)` | `createLightTokenTransferInstruction(...)` | +| **Signing** | Keypair signs directly | Smart wallet program signs via CPI | + +`transferInterface` rejects off-curve addresses. Use `createLightTokenTransferInstruction` instead. It accepts any `PublicKey`, including PDAs. Pass `allowOwnerOffCurve=true` (5th argument) when creating the associated token account. + +This pattern applies to any PDA-based wallet program. The examples below use [Squads Smart Accounts](https://squads.so). + + +The [full example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/smart-wallet) includes wallet creation, funding, sync transfer, and async governance flow with an integration test. + + + + + +## Prerequisites + +You need an existing smart wallet (PDA) and a ZK Compression-compatible RPC endpoint. + +```bash +npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @sqds/smart-account +``` + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; +import { + createAtaInterface, + getAssociatedTokenAddressInterface, + createLightTokenTransferInstruction, +} from "@lightprotocol/compressed-token"; +import * as smartAccount from "@sqds/smart-account"; + +// Use a ZK Compression endpoint (Helius, Triton, or self-hosted) +const rpc = createRpc(RPC_ENDPOINT); +``` + + + +If you don't have a smart wallet yet, create one with Squads. Set `timeLock: 0` for sync execution, or a positive value to require async governance. + +```typescript +const programConfig = + await smartAccount.accounts.ProgramConfig.fromAccountAddress( + rpc, + smartAccount.getProgramConfigPda({})[0] + ); +const accountIndex = + BigInt(programConfig.smartAccountIndex.toString()) + 1n; +const [settingsPda] = smartAccount.getSettingsPda({ accountIndex }); + +await smartAccount.rpc.createSmartAccount({ + connection: rpc, + treasury: programConfig.treasury, + creator: payer, + settings: settingsPda, + settingsAuthority: null, + threshold: 1, + signers: [ + { + key: payer.publicKey, + permissions: smartAccount.types.Permissions.all(), + }, + ], + timeLock: 0, + rentCollector: null, + sendOptions: { skipPreflight: true }, +}); +``` + + + +Snippets below assume `rpc`, `payer`, `mint`, `settingsPda`, and `walletPda` are defined. See the [full example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/smart-wallet) for runnable setup. + +## Create the wallet's token account + + + + + +The wallet PDA is derived by the smart wallet program. It is off-curve and cannot be used as a keypair. + +```typescript +const [walletPda] = smartAccount.getSmartAccountPda({ + settingsPda, + accountIndex: 0, +}); +``` + + + + + +Pass `true` as the 5th argument to allow the off-curve PDA as the token account owner: + +```typescript +await createAtaInterface(rpc, payer, mint, walletPda, true); +const walletAta = getAssociatedTokenAddressInterface(mint, walletPda, true); +``` + + + + + +## Fund the wallet + +Anyone can send Light Tokens to the wallet's associated token account. No smart wallet approval is needed. You can use `transferInterface` or `createLightTokenTransferInstruction` from any standard wallet: + +```typescript +const ix = createLightTokenTransferInstruction( + payerAta, // source + walletAta, // destination (the smart wallet's associated token account) + payer.publicKey, // owner of the source + amount // fee payer defaults to owner when omitted +); +``` + +The wallet PDA also needs SOL for inner transaction fees. Around 0.01 SOL is sufficient for many transfers: + +```typescript +import { SystemProgram } from "@solana/web3.js"; + +const fundIx = SystemProgram.transfer({ + fromPubkey: payer.publicKey, + toPubkey: walletPda, + lamports: 10_000_000, // 0.01 SOL +}); +``` + +## Send tokens from a smart wallet + + + + + +Use `createLightTokenTransferInstruction` to build the inner instruction. The wallet PDA is the owner. The optional 5th argument sets who pays rent top-ups. Pass `walletPda` so the wallet covers its own top-ups: + +```typescript +const transferIx = createLightTokenTransferInstruction( + walletAta, // source: wallet's Light Token associated token account + recipientAta, // destination + walletPda, // owner: the smart wallet PDA (off-curve) + amount, + walletPda // fee payer for rent top-ups (optional, defaults to owner) +); +``` + + + + + +The smart wallet program wraps your instruction and signs via CPI using the wallet PDA's seeds. + +Use **sync** when all signers are available and `timeLock=0`. The transfer happens in a single transaction. Use **async** when you need multi-party governance (threshold > 1 or time lock). + + + + +```typescript +import { + TransactionMessage, + VersionedTransaction, +} from "@solana/web3.js"; + +// Compile the inner instruction for synchronous execution +const { instructions, accounts } = + smartAccount.utils.instructionsToSynchronousTransactionDetails({ + vaultPda: walletPda, + members: [payer.publicKey], + transaction_instructions: [transferIx], + }); + +const syncIx = smartAccount.instructions.executeTransactionSync({ + settingsPda, + numSigners: 1, + accountIndex: 0, + instructions, + instruction_accounts: accounts, +}); + +// Send as a single transaction +const { blockhash } = await rpc.getLatestBlockhash(); +const msg = new TransactionMessage({ + payerKey: payer.publicKey, + recentBlockhash: blockhash, + instructions: [syncIx], +}).compileToV0Message(); + +const tx = new VersionedTransaction(msg); +tx.sign([payer]); +const sig = await rpc.sendRawTransaction(tx.serialize(), { + skipPreflight: true, +}); +await rpc.confirmTransaction(sig, "confirmed"); +``` + + + + +Each step is a separate transaction. This works with any threshold or time lock. + +```typescript +import { TransactionMessage } from "@solana/web3.js"; + +// Read the current transaction index +const settings = await smartAccount.accounts.Settings.fromAccountAddress( + rpc, + settingsPda +); +const txIndex = BigInt(settings.transactionIndex.toString()) + 1n; +const { blockhash } = await rpc.getLatestBlockhash(); + +// 1. Create the transaction +await smartAccount.rpc.createTransaction({ + connection: rpc, + feePayer: payer, + settingsPda, + transactionIndex: txIndex, + creator: payer.publicKey, + accountIndex: 0, + ephemeralSigners: 0, + transactionMessage: new TransactionMessage({ + payerKey: walletPda, + recentBlockhash: blockhash, + instructions: [transferIx], + }), + sendOptions: { skipPreflight: true }, +}); + +// 2. Create a proposal +await smartAccount.rpc.createProposal({ + connection: rpc, + feePayer: payer, + settingsPda, + transactionIndex: txIndex, + creator: payer, + sendOptions: { skipPreflight: true }, +}); + +// 3. Approve (repeat for each signer up to threshold) +await smartAccount.rpc.approveProposal({ + connection: rpc, + feePayer: payer, + settingsPda, + transactionIndex: txIndex, + signer: payer, + sendOptions: { skipPreflight: true }, +}); + +// 4. Execute +await smartAccount.rpc.executeTransaction({ + connection: rpc, + feePayer: payer, + settingsPda, + transactionIndex: txIndex, + signer: payer.publicKey, + signers: [payer], + sendOptions: { skipPreflight: true }, +}); +``` + + + + + + + + +## Check balance + +Query the wallet's token balance like any other account: + +```typescript +import { getAtaInterface } from "@lightprotocol/compressed-token/unified"; + +const account = await getAtaInterface(rpc, walletAta, walletPda, mint); +console.log(account.parsed.amount); +``` + +## Combine with gasless transactions + +You can sponsor the outer transaction fee so that only the wallet PDA's SOL is used for inner fees (rent top-ups). Set your application as `feePayer` on the outer transaction and pass it as the first signer: + +```typescript +// Outer transaction: your server pays the Solana network fee +const msg = new TransactionMessage({ + payerKey: sponsor.publicKey, // sponsor pays outer tx fee + recentBlockhash: blockhash, + instructions: [syncIx], +}).compileToV0Message(); + +const tx = new VersionedTransaction(msg); +tx.sign([sponsor, payer]); // sponsor + smart wallet signer +``` + +See [Gasless transactions](/light-token/wallets/gasless-transactions) for the full pattern. + +## Further reading + +- [Solana Smart Wallets](https://www.helius.dev/blog/solana-smart-wallets) : background on smart wallet concepts and account abstraction on Solana + + + + + + + +## Related guides + + + + Send a single token transfer. + + + Sponsor fees so users never hold SOL. + + + Full wallet integration reference. + + + + diff --git a/light-token/welcome.mdx b/light-token/welcome.mdx index 0cab3f6..d2aa169 100644 --- a/light-token/welcome.mdx +++ b/light-token/welcome.mdx @@ -29,8 +29,6 @@ import { lightCreateAtaMacroCode, } from "/snippets/code-samples/code-compare-snippets.jsx"; - **Note: This page is for the new Light Token Program Beta.**
For legacy - compressed tokens, please go [here](/resources/legacy-compressed-tokens).
### Mint Accounts diff --git a/scripts/copy-payments-snippets.sh b/scripts/copy-payments-snippets.sh new file mode 100755 index 0000000..2a0afa5 --- /dev/null +++ b/scripts/copy-payments-snippets.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +# Script to copy TypeScript code from examples-light-token payments to docs snippets. +# Wraps each file in typescript markdown code blocks. + +EXAMPLES="/home/tilo/Workspace/examples-light-token-main/toolkits/payments" +SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/payments" + +# Function to wrap TypeScript code in markdown +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" + echo "Created: $output_file" +} + +# Send examples +echo "Processing: send/" +for file in send-action send-instruction batch-send payment-with-memo sign-all-transactions; do + src="$EXAMPLES/send/$file.ts" + if [ -f "$src" ]; then + wrap_typescript "$src" "$SNIPPETS_DIR/send/$file.mdx" + else + echo " WARNING: Not found - $src" + fi +done + +# Receive examples +echo "Processing: receive/" +src="$EXAMPLES/receive/receive.ts" +if [ -f "$src" ]; then + wrap_typescript "$src" "$SNIPPETS_DIR/receive/receive.mdx" +else + echo " WARNING: Not found - $src" +fi + +# Verify examples +echo "Processing: verify/" +for file in get-balance get-history verify-address; do + src="$EXAMPLES/verify/$file.ts" + if [ -f "$src" ]; then + wrap_typescript "$src" "$SNIPPETS_DIR/verify/$file.mdx" + else + echo " WARNING: Not found - $src" + fi +done + +# Spend permissions examples +echo "Processing: spend-permissions/" +for file in delegate-approve delegate-revoke delegate-check delegate-full-flow; do + src="$EXAMPLES/spend-permissions/$file.ts" + if [ -f "$src" ]; then + wrap_typescript "$src" "$SNIPPETS_DIR/spend-permissions/$file.mdx" + else + echo " WARNING: Not found - $src" + fi +done + +# Interop examples +echo "Processing: interop/" +for file in wrap unwrap register-spl-mint; do + src="$EXAMPLES/interop/$file.ts" + if [ -f "$src" ]; then + wrap_typescript "$src" "$SNIPPETS_DIR/interop/$file.mdx" + else + echo " WARNING: Not found - $src" + fi +done + +echo "" +echo "Done! Created snippets in: $SNIPPETS_DIR" +echo "" +echo "Files created:" +find "$SNIPPETS_DIR" -name "*.mdx" -type f | sort \ No newline at end of file diff --git a/snippets/ai-prompts/wallets/smart-wallets.mdx b/snippets/ai-prompts/wallets/smart-wallets.mdx new file mode 100644 index 0000000..a61a780 --- /dev/null +++ b/snippets/ai-prompts/wallets/smart-wallets.mdx @@ -0,0 +1,159 @@ + +{`--- +description: Smart wallet integration with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Smart wallet integration with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/wallets/smart-wallets +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Full example: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/smart-wallet +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @sqds/smart-account + +How smart wallets differ from standard wallets: +- The wallet is a PDA (off-curve) and not a valid keypair +- \`transferInterface()\` and \`createTransferInterfaceInstructions()\` reject off-curve addresses +- Use \`createLightTokenTransferInstruction()\` instead. It accepts any PublicKey +- Associated token account creation needs \`allowOwnerOffCurve=true\`: \`createAtaInterface(rpc, payer, mint, walletPda, true)\` +- The smart wallet program signs via CPI, not with a keypair + +Key APIs: +| Function | Purpose | Off-curve note | +| \`createLightTokenTransferInstruction(src, dest, owner, amount, feePayer?)\` | Build transfer instruction | Accepts any PublicKey as owner | +| \`createAtaInterface(rpc, payer, mint, owner, allowOwnerOffCurve?)\` | Create associated token account | 5th arg must be \`true\` for PDAs | +| \`smartAccount.instructions.executeTransactionSync()\` | Sync execution | Single tx, all signers + timeLock=0 | +| \`smartAccount.rpc.createTransaction/createProposal/approveProposal/executeTransaction\` | Async governance flow | Multi-step, any threshold | + +### 1. Index project +- Grep \`smartAccount|createLightTokenTransferInstruction|@sqds|@lightprotocol|allowOwnerOffCurve|walletPda\` across src/ +- Glob \`**/*.ts\` and \`**/*.tsx\` for project structure +- Identify: existing smart wallet setup, token operations, execution mode (sync vs async) +- Check package.json for @lightprotocol/*, @sqds/smart-account dependencies +- Task subagent (Grep/Read/WebFetch) if project has multiple packages + +### 2. Read references +- WebFetch the guide above. Review code examples for off-curve ATA and transfer patterns +- WebFetch skill.md. Check for dedicated skill and resources +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (add Light Token support to existing smart wallet, new integration from scratch, migrate from SPL to Light Token) +- AskUserQuestion: which smart wallet program? (Squads, custom, other) +- AskUserQuestion: sync execution, async governance, or both? +- AskUserQuestion: does the wallet already exist on-chain or needs creation? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft implementation plan +- Key patterns: + - \`createAtaInterface(rpc, payer, mint, walletPda, true)\` for off-curve ATA + - \`createLightTokenTransferInstruction(src, dest, walletPda, amount, walletPda)\` for transfers + - Wrap in smart wallet execution (sync or async depending on config) +- If anything is unclear, loop back to step 3 +- Present the plan to the user for approval + +### 5. Implement +- Add deps if missing: \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @sqds/smart-account\` +- Set up RPC: \`createRpc(RPC_ENDPOINT)\` with a ZK Compression endpoint (Helius, Triton) +- Import \`createLightTokenTransferInstruction\`, \`createAtaInterface\`, \`getAssociatedTokenAddressInterface\` from \`@lightprotocol/compressed-token\` +- Create off-curve associated token account for the wallet PDA +- Build transfer instruction with wallet PDA as owner +- Wrap in smart wallet execution (sync: \`executeTransactionSync\`, async: createTransaction → createProposal → approveProposal → executeTransaction) +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash \`tsc --noEmit\` +- Bash run existing test suite if present +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work`} + + +```text +--- +description: Smart wallet integration with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Smart wallet integration with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/wallets/smart-wallets +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Full example: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/smart-wallet +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @sqds/smart-account + +How smart wallets differ from standard wallets: +- The wallet is a PDA (off-curve) and not a valid keypair +- `transferInterface()` and `createTransferInterfaceInstructions()` reject off-curve addresses +- Use `createLightTokenTransferInstruction()` instead. It accepts any PublicKey +- ATA creation needs `allowOwnerOffCurve=true`: `createAtaInterface(rpc, payer, mint, walletPda, true)` +- The smart wallet program signs via CPI, not with a keypair + +Key APIs: +| Function | Purpose | Off-curve note | +| `createLightTokenTransferInstruction(src, dest, owner, amount, feePayer?)` | Build transfer instruction | Accepts any PublicKey as owner | +| `createAtaInterface(rpc, payer, mint, owner, allowOwnerOffCurve?)` | Create associated token account | 5th arg must be `true` for PDAs | +| `smartAccount.instructions.executeTransactionSync()` | Sync execution | Single tx, all signers + timeLock=0 | +| `smartAccount.rpc.createTransaction/createProposal/approveProposal/executeTransaction` | Async governance flow | Multi-step, any threshold | + +### 1. Index project +- Grep `smartAccount|createLightTokenTransferInstruction|@sqds|@lightprotocol|allowOwnerOffCurve|walletPda` across src/ +- Glob `**/*.ts` and `**/*.tsx` for project structure +- Identify: existing smart wallet setup, token operations, execution mode (sync vs async) +- Check package.json for @lightprotocol/*, @sqds/smart-account dependencies +- Task subagent (Grep/Read/WebFetch) if project has multiple packages + +### 2. Read references +- WebFetch the guide above. Review code examples for off-curve ATA and transfer patterns +- WebFetch skill.md. Check for dedicated skill and resources +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (add Light Token support to existing smart wallet, new integration from scratch, migrate from SPL to Light Token) +- AskUserQuestion: which smart wallet program? (Squads, custom, other) +- AskUserQuestion: sync execution, async governance, or both? +- AskUserQuestion: does the wallet already exist on-chain or needs creation? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft implementation plan +- Key patterns: + - `createAtaInterface(rpc, payer, mint, walletPda, true)` for off-curve ATA + - `createLightTokenTransferInstruction(src, dest, walletPda, amount, walletPda)` for transfers + - Wrap in smart wallet execution (sync or async depending on config) +- If anything is unclear, loop back to step 3 +- Present the plan to the user for approval + +### 5. Implement +- Add deps if missing: `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @sqds/smart-account` +- Set up RPC: `createRpc(RPC_ENDPOINT)` with a ZK Compression endpoint (Helius, Triton) +- Import `createLightTokenTransferInstruction`, `createAtaInterface`, `getAssociatedTokenAddressInterface` from `@lightprotocol/compressed-token` +- Create off-curve associated token account for the wallet PDA +- Build transfer instruction with wallet PDA as owner +- Wrap in smart wallet execution (sync: `executeTransactionSync`, async: createTransaction → createProposal → approveProposal → executeTransaction) +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash `tsc --noEmit` +- Bash run existing test suite if present +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work +``` diff --git a/snippets/code-snippets/payments/interop/register-spl-mint.mdx b/snippets/code-snippets/payments/interop/register-spl-mint.mdx new file mode 100644 index 0000000..3494b3c --- /dev/null +++ b/snippets/code-snippets/payments/interop/register-spl-mint.mdx @@ -0,0 +1,46 @@ +```typescript +import "dotenv/config"; +import { + Keypair, + PublicKey, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { TOKEN_PROGRAM_ID } from "@solana/spl-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 () { + // Replace with your existing SPL mint (e.g. USDC) + const mint = new PublicKey("YOUR_EXISTING_MINT_ADDRESS"); + + // One-time: Register the SPL interface PDA for this mint. + // This creates the omnibus account that holds SPL tokens when wrapped to light-token. + // Note: createMintInterface(... TOKEN_PROGRAM_ID) does this automatically for new mints. + const ix = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint, + tokenProgramId: TOKEN_PROGRAM_ID, + }); + + const tx = new Transaction().add(ix); + const signature = await sendAndConfirmTransaction(rpc, tx, [payer]); + + console.log("Mint:", mint.toBase58()); + console.log("Tx:", signature); +})(); +``` diff --git a/snippets/code-snippets/payments/interop/unwrap.mdx b/snippets/code-snippets/payments/interop/unwrap.mdx new file mode 100644 index 0000000..81f0342 --- /dev/null +++ b/snippets/code-snippets/payments/interop/unwrap.mdx @@ -0,0 +1,68 @@ +```typescript +import "dotenv/config"; +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { + createMintInterface, + createAtaInterface, + getAssociatedTokenAddressInterface, +} from "@lightprotocol/compressed-token"; +import { wrap, unwrap } from "@lightprotocol/compressed-token/unified"; +import { + TOKEN_PROGRAM_ID, + createAssociatedTokenAccount, + mintTo, +} from "@solana/spl-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 () { + // 1. Create SPL mint (includes SPL interface PDA registration) + const { mint } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + undefined, + undefined, + TOKEN_PROGRAM_ID + ); + + // 2. Create SPL ATA and mint tokens + const splAta = await createAssociatedTokenAccount( + rpc, + payer, + mint, + payer.publicKey, + undefined, + TOKEN_PROGRAM_ID + ); + await mintTo(rpc, payer, mint, splAta, payer, 1000); + + // 3. Create light-token ATA and wrap all SPL tokens into it + await createAtaInterface(rpc, payer, mint, payer.publicKey); + const senderAta = getAssociatedTokenAddressInterface( + mint, + payer.publicKey + ); + await wrap(rpc, payer, splAta, senderAta, payer, mint, BigInt(1000)); + + // 4. Unwrap: move tokens back from light-token to SPL ATA + const tx = await unwrap(rpc, payer, splAta, payer, mint, 500); + + console.log("Tx:", tx); +})(); +``` diff --git a/snippets/code-snippets/payments/interop/wrap.mdx b/snippets/code-snippets/payments/interop/wrap.mdx new file mode 100644 index 0000000..1caafd9 --- /dev/null +++ b/snippets/code-snippets/payments/interop/wrap.mdx @@ -0,0 +1,75 @@ +```typescript +import "dotenv/config"; +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { + createMintInterface, + createAtaInterface, + getAssociatedTokenAddressInterface, +} from "@lightprotocol/compressed-token"; +import { wrap } from "@lightprotocol/compressed-token/unified"; +import { + TOKEN_PROGRAM_ID, + createAssociatedTokenAccount, + mintTo, +} from "@solana/spl-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 () { + // 1. Create SPL mint (includes SPL interface PDA registration) + const { mint } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + undefined, + undefined, + TOKEN_PROGRAM_ID + ); + + // 2. Create SPL ATA and mint tokens + const splAta = await createAssociatedTokenAccount( + rpc, + payer, + mint, + payer.publicKey, + undefined, + TOKEN_PROGRAM_ID + ); + await mintTo(rpc, payer, mint, splAta, payer, 1000); + + // 3. Create light-token ATA + await createAtaInterface(rpc, payer, mint, payer.publicKey); + const senderAta = getAssociatedTokenAddressInterface( + mint, + payer.publicKey + ); + + // 4. Wrap: move SPL tokens into the light-token system + const tx = await wrap( + rpc, + payer, + splAta, + senderAta, + payer, + mint, + BigInt(500) + ); + + console.log("Tx:", tx); +})(); +``` diff --git a/snippets/code-snippets/payments/receive/receive.mdx b/snippets/code-snippets/payments/receive/receive.mdx new file mode 100644 index 0000000..3501d75 --- /dev/null +++ b/snippets/code-snippets/payments/receive/receive.mdx @@ -0,0 +1,53 @@ +```typescript +import { + Keypair, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; +import { + getAssociatedTokenAddressInterface, + transferInterface, + createLoadAtaInstructions, +} from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint, senderAta } = await setup(); + + // Transfer to a fresh recipient so they have cold tokens + const recipient = Keypair.generate(); + await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); + const recipientAta = getAssociatedTokenAddressInterface( + mint, + recipient.publicKey + ); + await transferInterface( + rpc, + payer, + senderAta, + mint, + recipientAta, + payer, + 500 + ); + + // --- Receive: load creates ATA if needed + pulls cold state to hot --- + // Returns TransactionInstruction[][]. Each inner array is one txn. + // Almost always one. Empty = noop. + const instructions = await createLoadAtaInstructions( + rpc, + recipientAta, + recipient.publicKey, + mint, + payer.publicKey + ); + + for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer]); + } + + console.log("Recipient ATA:", recipientAta.toBase58()); +})(); +``` diff --git a/snippets/code-snippets/payments/send/batch-send.mdx b/snippets/code-snippets/payments/send/batch-send.mdx new file mode 100644 index 0000000..50e5e18 --- /dev/null +++ b/snippets/code-snippets/payments/send/batch-send.mdx @@ -0,0 +1,75 @@ +```typescript +import { + Keypair, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { + createAtaInterfaceIdempotent, + getAssociatedTokenAddressInterface, + getAtaInterface, +} from "@lightprotocol/compressed-token"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + // Step 1: Setup — create mint and fund sender + const { mint } = await setup(); + + const recipients = Array.from({ length: 5 }, (_, i) => ({ + address: Keypair.generate().publicKey, + amount: (i + 1) * 100, + })); + + // Step 2: Create ATAs idempotently for sender + all recipients + await createAtaInterfaceIdempotent(rpc, payer, mint, payer.publicKey); + for (const { address } of recipients) { + await createAtaInterfaceIdempotent(rpc, payer, mint, address); + } + + // Step 3: Derive ATA addresses + const senderAta = getAssociatedTokenAddressInterface(mint, payer.publicKey); + const recipientAtas = recipients.map(({ address }) => + getAssociatedTokenAddressInterface(mint, address) + ); + + // Step 4: Create transfer instructions + const COMPUTE_BUDGET_ID = + "ComputeBudget111111111111111111111111111111"; + const allTransferIxs = []; + let isFirst = true; + + for (const { address, amount } of recipients) { + const destination = getAssociatedTokenAddressInterface(mint, address); + const ixs = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + payer.publicKey, + destination + ); + // Deduplicate ComputeBudget across transfers. + for (const ix of ixs[0]) { + if (!isFirst && ix.programId.toBase58() === COMPUTE_BUDGET_ID) + continue; + allTransferIxs.push(ix); + } + isFirst = false; + } + + // Step 5: Batch into single transaction + const batchTx = new Transaction().add(...allTransferIxs); + const sig = await sendAndConfirmTransaction(rpc, batchTx, [payer]); + console.log("Batch tx:", sig); + + // Step 6: Verify balances + for (const { address, amount } of recipients) { + const ata = getAssociatedTokenAddressInterface(mint, address); + const { parsed } = await getAtaInterface(rpc, ata, address, mint); + console.log( + ` ${address.toBase58()}: ${parsed.amount} (expected ${amount})` + ); + } +})(); +``` diff --git a/snippets/code-snippets/payments/send/payment-with-memo.mdx b/snippets/code-snippets/payments/send/payment-with-memo.mdx new file mode 100644 index 0000000..9a536c8 --- /dev/null +++ b/snippets/code-snippets/payments/send/payment-with-memo.mdx @@ -0,0 +1,71 @@ +```typescript +import { + Keypair, + Transaction, + TransactionInstruction, + PublicKey, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; +import { + getAssociatedTokenAddressInterface, + createTransferInterfaceInstructions, + sliceLast, +} from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +const MEMO_PROGRAM_ID = new PublicKey( + "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr" +); + +(async function () { + const { mint } = await setup(); + + const recipient = Keypair.generate(); + await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); + const destination = getAssociatedTokenAddressInterface( + mint, + recipient.publicKey + ); + + const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + 100, + payer.publicKey, + destination + ); + + const { rest: loadInstructions, last: transferInstructions } = + sliceLast(instructions); + + // Send load transactions first (if any) + for (const ixs of loadInstructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer]); + } + + // Add memo to the transfer transaction + const memoIx = new TransactionInstruction({ + keys: [], + programId: MEMO_PROGRAM_ID, + data: Buffer.from("INV-2024-001"), + }); + + const transferTx = new Transaction().add(...transferInstructions, memoIx); + const signature = await sendAndConfirmTransaction(rpc, transferTx, [payer]); + console.log("Tx with memo:", signature); + + // Read memo back from transaction logs + const txDetails = await rpc.getTransaction(signature, { + maxSupportedTransactionVersion: 0, + }); + + const logs = txDetails?.meta?.logMessages || []; + const memoLogs = logs.filter((log: string) => + log.includes("Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr") + ); + console.log("Memo logs:", memoLogs); +})(); +``` diff --git a/snippets/code-snippets/payments/send/send-action.mdx b/snippets/code-snippets/payments/send/send-action.mdx new file mode 100644 index 0000000..cea53f6 --- /dev/null +++ b/snippets/code-snippets/payments/send/send-action.mdx @@ -0,0 +1,32 @@ +```typescript +import { Keypair } from "@solana/web3.js"; +import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; +import { + getAssociatedTokenAddressInterface, + transferInterface, +} from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint, senderAta } = await setup(); + + const recipient = Keypair.generate(); + await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); + const recipientAta = getAssociatedTokenAddressInterface( + mint, + recipient.publicKey + ); + + const sig = await transferInterface( + rpc, + payer, + senderAta, + mint, + recipientAta, + payer, + 100 + ); + + console.log("Tx:", sig); +})(); +``` diff --git a/snippets/code-snippets/payments/send/send-instruction.mdx b/snippets/code-snippets/payments/send/send-instruction.mdx new file mode 100644 index 0000000..5991ac0 --- /dev/null +++ b/snippets/code-snippets/payments/send/send-instruction.mdx @@ -0,0 +1,40 @@ +```typescript +import { + Keypair, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; +import { + getAssociatedTokenAddressInterface, + createTransferInterfaceInstructions, +} from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint } = await setup(); + + const recipient = Keypair.generate(); + await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); + const destination = getAssociatedTokenAddressInterface( + mint, + recipient.publicKey + ); + + // Returns TransactionInstruction[][]. Each inner array is one txn. + const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + 100, + payer.publicKey, + destination + ); + + for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + const sig = await sendAndConfirmTransaction(rpc, tx, [payer]); + console.log("Tx:", sig); + } +})(); +``` diff --git a/snippets/code-snippets/payments/send/sign-all-transactions.mdx b/snippets/code-snippets/payments/send/sign-all-transactions.mdx new file mode 100644 index 0000000..80f13f8 --- /dev/null +++ b/snippets/code-snippets/payments/send/sign-all-transactions.mdx @@ -0,0 +1,70 @@ +```typescript +import { + Keypair, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; +import { + getAssociatedTokenAddressInterface, + createTransferInterfaceInstructions, + sliceLast, +} from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint } = await setup(); + + const recipient = Keypair.generate(); + await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); + const destination = getAssociatedTokenAddressInterface( + mint, + recipient.publicKey + ); + + const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + 100, + payer.publicKey, + destination + ); + + // --- Sign all transactions together — one approval for all --- + const transactions = instructions.map( + (ixs) => new Transaction().add(...ixs) + ); + // In a wallet context: await wallet.signAllTransactions(transactions) + for (const tx of transactions) { + const sig = await sendAndConfirmTransaction(rpc, tx, [payer]); + console.log("Tx:", sig); + } + + // --- Parallel optimization: parallelize loads, then send transfer --- + const instructions2 = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + 50, + payer.publicKey, + destination + ); + + const { rest: loadInstructions, last: transferInstructions } = + sliceLast(instructions2); + + // Parallelize loads (empty = nothing to load, will no-op) + await Promise.all( + loadInstructions.map((ixs) => { + const tx = new Transaction().add(...ixs); + return sendAndConfirmTransaction(rpc, tx, [payer]); + }) + ); + + // Send transfer after all loads confirm + const transferTx = new Transaction().add(...transferInstructions); + const sig = await sendAndConfirmTransaction(rpc, transferTx, [payer]); + console.log("Parallel optimized Tx:", sig); +})(); +``` diff --git a/snippets/code-snippets/payments/spend-permissions/delegate-approve.mdx b/snippets/code-snippets/payments/spend-permissions/delegate-approve.mdx new file mode 100644 index 0000000..6047ea3 --- /dev/null +++ b/snippets/code-snippets/payments/spend-permissions/delegate-approve.mdx @@ -0,0 +1,25 @@ +```typescript +import { Keypair } from "@solana/web3.js"; +import { approveInterface } from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint, senderAta } = await setup(); + + // Approve: grant delegate permission to spend up to 500,000 tokens + const delegate = Keypair.generate(); + const tx = await approveInterface( + rpc, + payer, + senderAta, + mint, + delegate.publicKey, + 500_000, + payer + ); + + console.log("Approved delegate:", delegate.publicKey.toBase58()); + console.log("Allowance: 500,000 tokens"); + console.log("Tx:", tx); +})(); +``` diff --git a/snippets/code-snippets/payments/spend-permissions/delegate-check.mdx b/snippets/code-snippets/payments/spend-permissions/delegate-check.mdx new file mode 100644 index 0000000..48e0181 --- /dev/null +++ b/snippets/code-snippets/payments/spend-permissions/delegate-check.mdx @@ -0,0 +1,60 @@ +```typescript +import { Keypair } from "@solana/web3.js"; +import { getAtaInterface } from "@lightprotocol/compressed-token"; +import { approveInterface } from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint, senderAta } = await setup(); + + // Check before approval — no delegate set + const beforeApproval = await getAtaInterface( + rpc, + senderAta, + payer.publicKey, + mint + ); + console.log("Before approval:"); + console.log( + " Delegate:", + beforeApproval.parsed.delegate?.toBase58() ?? "none" + ); + console.log( + " Delegated amount:", + beforeApproval.parsed.delegatedAmount.toString() + ); + + // Approve delegate + const delegate = Keypair.generate(); + await approveInterface( + rpc, + payer, + senderAta, + mint, + delegate.publicKey, + 500_000, + payer + ); + + // Check after approval — delegate is set with allowance + const afterApproval = await getAtaInterface( + rpc, + senderAta, + payer.publicKey, + mint + ); + console.log("\nAfter approval:"); + console.log( + " Delegate:", + afterApproval.parsed.delegate?.toBase58() ?? "none" + ); + console.log( + " Delegated amount:", + afterApproval.parsed.delegatedAmount.toString() + ); + console.log( + " Account balance:", + afterApproval.parsed.amount.toString() + ); +})(); +``` diff --git a/snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx b/snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx new file mode 100644 index 0000000..18499f3 --- /dev/null +++ b/snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx @@ -0,0 +1,65 @@ +```typescript +import { Keypair } from "@solana/web3.js"; +import { getAtaInterface } from "@lightprotocol/compressed-token"; +import { + approveInterface, + revokeInterface, +} from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint, senderAta } = await setup(); + + // 1. Owner approves delegate to spend up to 500,000 tokens + const delegate = Keypair.generate(); + const approveTx = await approveInterface( + rpc, + payer, + senderAta, + mint, + delegate.publicKey, + 500_000, + payer + ); + console.log("1. Approved delegate:", delegate.publicKey.toBase58()); + console.log(" Allowance: 500,000 tokens"); + console.log(" Tx:", approveTx); + + // 2. Check delegation status + const account = await getAtaInterface( + rpc, + senderAta, + payer.publicKey, + mint + ); + console.log("\n2. Account status after approval:"); + console.log( + " Delegate:", + account.parsed.delegate?.toBase58() ?? "none" + ); + console.log( + " Delegated amount:", + account.parsed.delegatedAmount.toString() + ); + console.log(" Account balance:", account.parsed.amount.toString()); + + // 3. Owner revokes all delegate permissions + const revokeTx = await revokeInterface(rpc, payer, senderAta, mint, payer); + console.log("\n3. Revoked all delegate permissions"); + console.log(" Tx:", revokeTx); + + // 4. Verify delegate is removed + const afterRevoke = await getAtaInterface( + rpc, + senderAta, + payer.publicKey, + mint + ); + console.log("\n4. Account status after revoke:"); + console.log( + " Delegate:", + afterRevoke.parsed.delegate?.toBase58() ?? "none" + ); + console.log(" Balance:", afterRevoke.parsed.amount.toString()); +})(); +``` diff --git a/snippets/code-snippets/payments/spend-permissions/delegate-revoke.mdx b/snippets/code-snippets/payments/spend-permissions/delegate-revoke.mdx new file mode 100644 index 0000000..9c1126e --- /dev/null +++ b/snippets/code-snippets/payments/spend-permissions/delegate-revoke.mdx @@ -0,0 +1,31 @@ +```typescript +import { Keypair } from "@solana/web3.js"; +import { + approveInterface, + revokeInterface, +} from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint, senderAta } = await setup(); + + // Approve delegate + const delegate = Keypair.generate(); + await approveInterface( + rpc, + payer, + senderAta, + mint, + delegate.publicKey, + 500_000, + payer + ); + console.log("Approved delegate:", delegate.publicKey.toBase58()); + + // Revoke all delegate permissions + const tx = await revokeInterface(rpc, payer, senderAta, mint, payer); + + console.log("Revoked all delegate permissions"); + console.log("Tx:", tx); +})(); +``` diff --git a/snippets/code-snippets/payments/verify/get-balance.mdx b/snippets/code-snippets/payments/verify/get-balance.mdx new file mode 100644 index 0000000..7192a57 --- /dev/null +++ b/snippets/code-snippets/payments/verify/get-balance.mdx @@ -0,0 +1,41 @@ +```typescript +import { Keypair } from "@solana/web3.js"; +import { + createAtaInterfaceIdempotent, + getAtaInterface, +} from "@lightprotocol/compressed-token"; +import { + getAssociatedTokenAddressInterface, + transferInterface, +} from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint, senderAta } = await setup(); + + const recipient = Keypair.generate(); + await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); + const recipientAta = getAssociatedTokenAddressInterface( + mint, + recipient.publicKey + ); + await transferInterface( + rpc, + payer, + senderAta, + mint, + recipientAta, + payer, + 100 + ); + + // Get recipient's balance + const { parsed: account } = await getAtaInterface( + rpc, + recipientAta, + recipient.publicKey, + mint + ); + console.log("Recipient's balance:", account.amount); +})(); +``` diff --git a/snippets/code-snippets/payments/verify/get-history.mdx b/snippets/code-snippets/payments/verify/get-history.mdx new file mode 100644 index 0000000..2d8398a --- /dev/null +++ b/snippets/code-snippets/payments/verify/get-history.mdx @@ -0,0 +1,33 @@ +```typescript +import { Keypair } from "@solana/web3.js"; +import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; +import { + getAssociatedTokenAddressInterface, + transferInterface, +} from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint, senderAta } = await setup(); + + const recipient = Keypair.generate(); + await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); + const recipientAta = getAssociatedTokenAddressInterface( + mint, + recipient.publicKey + ); + await transferInterface( + rpc, + payer, + senderAta, + mint, + recipientAta, + payer, + 100 + ); + + // Get transaction history + const result = await rpc.getSignaturesForOwnerInterface(payer.publicKey); + console.log("Signatures:", result.signatures.length); +})(); +``` diff --git a/snippets/code-snippets/payments/verify/verify-address.mdx b/snippets/code-snippets/payments/verify/verify-address.mdx new file mode 100644 index 0000000..c127f07 --- /dev/null +++ b/snippets/code-snippets/payments/verify/verify-address.mdx @@ -0,0 +1,61 @@ +```typescript +import { Keypair } from "@solana/web3.js"; +import { + createMintInterface, + createAtaInterface, + getAssociatedTokenAddressInterface, + getAtaInterface, +} from "@lightprotocol/compressed-token"; +import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; +import { rpc, payer } from "../setup.js"; + +(async function () { + const { mint } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + undefined, + undefined, + TOKEN_PROGRAM_ID + ); + + // Create an associated token account for the payer (so it exists) + await createAtaInterface(rpc, payer, mint, payer.publicKey); + + // --- Verify an address that HAS an associated token account --- + const existingRecipient = payer.publicKey; + const expectedAta = getAssociatedTokenAddressInterface( + mint, + existingRecipient + ); + + try { + const account = await getAtaInterface( + rpc, + expectedAta, + existingRecipient, + mint + ); + console.log("Account exists, balance:", account.parsed.amount); + } catch { + console.log( + "Account does not exist yet — will be created on first transfer" + ); + } + + // --- Verify an address that does NOT have an associated token account --- + const newRecipient = Keypair.generate().publicKey; + const newAta = getAssociatedTokenAddressInterface(mint, newRecipient); + + try { + const account = await getAtaInterface(rpc, newAta, newRecipient, mint); + console.log("Account exists, balance:", account.parsed.amount); + } catch { + console.log( + "Account does not exist yet — will be created on first transfer" + ); + } +})(); +``` From 87b6ddbbd691df63674091679291a5825a88bbc2 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Thu, 19 Mar 2026 01:08:03 +0000 Subject: [PATCH 05/19] add payment --- docs.json | 25 +++++++++++-- light-token/payments/overview.mdx | 2 +- light-token/payments/payment-with-memo.mdx | 5 +-- light-token/payments/production-readiness.mdx | 21 ----------- light-token/payments/receive-payments.mdx | 29 ++++----------- light-token/payments/spend-permissions.mdx | 37 ++++++------------- .../payments/verify-recipient-address.mdx | 5 +-- light-token/payments/wrap-unwrap.mdx | 11 +----- ...e-nullifier-pdas.mdx => nullifier-pda.mdx} | 0 9 files changed, 45 insertions(+), 90 deletions(-) rename pda/compressed-pdas/{how-to-create-nullifier-pdas.mdx => nullifier-pda.mdx} (100%) diff --git a/docs.json b/docs.json index 6c61979..a02e52d 100644 --- a/docs.json +++ b/docs.json @@ -73,8 +73,14 @@ "light-token/payments/verify-recipient-address" ] }, - "light-token/payments/spend-permissions", "light-token/payments/wrap-unwrap", + { + "group": "Advanced", + "pages": [ + "light-token/payments/spend-permissions", + "pda/compressed-pdas/nullifier-pda" + ] + }, "light-token/payments/production-readiness" ] }, @@ -122,7 +128,6 @@ "pages": [ "pda/compressed-pdas/overview", "pda/compressed-pdas/guides/client-guide", - "pda/compressed-pdas/how-to-create-nullifier-pdas", { "group": "Program Guides", "expanded": true, @@ -336,6 +341,18 @@ } }, "redirects": [ + { + "source": "/pda/compressed-pdas/how-to-create-nullifier-pdas", + "destination": "https://zkcompression.com/pda/compressed-pdas/nullifier-pda" + }, + { + "source": "/light-token/payments/nullifier-pda", + "destination": "https://zkcompression.com/pda/compressed-pdas/nullifier-pda" + }, + { + "source": "/light-token/nullifier-pda", + "destination": "https://zkcompression.com/pda/compressed-pdas/nullifier-pda" + }, { "source": "/airdrop", "destination": "https://zkcompression.com/token-distribution" @@ -438,7 +455,7 @@ }, { "source": "/compressed-pdas/guides/how-to-create-nullifier-pdas", - "destination": "https://zkcompression.com/pda/compressed-pdas/how-to-create-nullifier-pdas" + "destination": "https://zkcompression.com/pda/compressed-pdas/nullifier-pda" }, { "source": "/compressed-pdas/guides/how-to-reinitialize-compressed-accounts", @@ -978,7 +995,7 @@ }, { "source": "/pda/compressed-pdas/guides/how-to-create-nullifier-pdas", - "destination": "https://zkcompression.com/pda/compressed-pdas/how-to-create-nullifier-pdas" + "destination": "https://zkcompression.com/pda/compressed-pdas/nullifier-pda" } ] } diff --git a/light-token/payments/overview.mdx b/light-token/payments/overview.mdx index df89cbe..20da49b 100644 --- a/light-token/payments/overview.mdx +++ b/light-token/payments/overview.mdx @@ -113,7 +113,7 @@ Learn more on extensions here: [Extensions](https://solana.com/docs/tokens/exten ### Signing - + ### Go to Production diff --git a/light-token/payments/payment-with-memo.mdx b/light-token/payments/payment-with-memo.mdx index 7bfe810..d543f4f 100644 --- a/light-token/payments/payment-with-memo.mdx +++ b/light-token/payments/payment-with-memo.mdx @@ -1,7 +1,7 @@ --- title: "Payment with Memo" sidebarTitle: "Payment with Memo" -description: "Attach invoice IDs, payment references, or notes to Light Token transfers using the memo program." +description: "Attach invoice IDs, payment references, or notes to Light Token transfers using Solana's memo program. The memo is recorded in the transaction logs for reconciliation." keywords: ["memo payment solana", "invoice reconciliation solana", "payment reference light token", "memo instruction"] --- @@ -10,9 +10,6 @@ import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; -Attach metadata like invoice IDs or payment references to a Light Token transfer -using Solana's memo program. The memo is recorded in the transaction logs for reconciliation. - diff --git a/light-token/payments/production-readiness.mdx b/light-token/payments/production-readiness.mdx index d1174af..7ded428 100644 --- a/light-token/payments/production-readiness.mdx +++ b/light-token/payments/production-readiness.mdx @@ -80,13 +80,6 @@ Set your application as the fee payer so users never interact with SOL: 1. **Rent top-ups and transaction fees**: Set `payer` parameter on Light Token instructions. See [gasless transactions](/light-token/wallets/gasless-transactions). 2. **Rent sponsor funding**: Ensure the rent sponsor PDA is funded. See the [cost breakdown](/light-token/wallets/gasless-transactions) for required amounts. -## Security - -- **Key management**: Use hardware security modules (HSMs) or managed key services for production signing keys. -- **Signing infrastructure**: Separate hot wallets (for automated operations) from cold wallets (for treasury). -- **Address verification**: Validate recipient addresses before sending. See [verify address](/light-token/payments/verify-recipient-address). -- **Monitoring**: Track transaction success rates, cold account loading frequency, and fee payer SOL balance. - ## Pre-launch checklist - [ ] Photon-compatible RPC endpoint configured and tested @@ -106,18 +99,4 @@ Set your application as the fee payer so users never interact with SOL: -## Related guides - - - - Abstract fees for users. - - - Send a single transfer. - - - Load cold accounts and prepare to receive. - - - \ No newline at end of file diff --git a/light-token/payments/receive-payments.mdx b/light-token/payments/receive-payments.mdx index 36530da..da5c3d0 100644 --- a/light-token/payments/receive-payments.mdx +++ b/light-token/payments/receive-payments.mdx @@ -14,28 +14,6 @@ import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; 2. We recommend to prepend a load instruction before. Load creates the associated token account if needed and loads any cold balance into it. -
- - - - - - - - - - - - - - -
SPLLight
**Receive**getOrCreateAssociatedTokenAccount()createLoadAtaInstructions()
- - - - - - **About loading**: Light Token accounts reduce account rent ~200x by auto-compressing inactive accounts. Before any action, the SDK detects cold balances and adds @@ -44,6 +22,13 @@ atomic transaction with your regular transfer. APIs return `TransactionInstructi loop handles the rare multi-transaction case automatically. + + + + + + + ## Setup diff --git a/light-token/payments/spend-permissions.mdx b/light-token/payments/spend-permissions.mdx index 631951b..63ddf9d 100644 --- a/light-token/payments/spend-permissions.mdx +++ b/light-token/payments/spend-permissions.mdx @@ -1,7 +1,7 @@ --- -title: "Spend Permissions" +title: "Spend Permissions via Delegation" sidebarTitle: "Spend Permissions" -description: "Delegate token spending to third parties with amount caps for subscriptions, recurring payments, and managed spending." +description: "Delegate token spending to a third party with an amount cap. The delegate can transfer tokens on behalf of the owner up to the approved amount, without the owner signing each transaction." keywords: ["delegate tokens solana", "token delegation light token", "spend permissions solana", "recurring payments solana"] --- @@ -10,9 +10,15 @@ import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; -Delegate token spending to a third party with an amount cap. -The delegate can transfer tokens on behalf of the owner up to the approved amount, -without the owner signing each transaction. +--- + +Delegation with Light Token works similar to SPL. +When you approve a delegate, you're authorizing a specific account to transfer tokens on your behalf: + +- **Owner retains custody**: You still own the tokens and can transfer or revoke at any time. Delegation is non-custodial. +- **Capped spending**: The delegate can spend tokens up to the limit, but cannot access or drain the account beyond the approved amount. +- **Single delegate per account**: Each token account can only have one active delegate. The owner can revoke at any time. +- **New approval replaces old**: Approving a new delegate automatically revokes the previous one @@ -105,27 +111,6 @@ const tx = await revokeInterface(rpc, payer, senderAta, mint, owner); console.log("Revoked:", tx); ``` -## Security considerations - -- **Amount caps**: Always set the minimum amount needed. Delegation does not grant unlimited access. -- **Single delegate**: Each compressed token account supports one active delegate at a time. -- **Monitor usage**: Query `getAtaInterface` regularly to track delegate activity. -- **Revoke promptly**: Remove delegation when the business relationship ends or the spending period expires. - -## Delegation vs. custody - -| | Delegation | Custody | -|:--|:-----------|:--------| -| **Key control** | Owner retains private key | Third party holds private key | -| **Spending limit** | Capped at approved amount | Unlimited | -| **Revocable** | Owner can revoke at any time | Requires key transfer back | -| **Use case** | Subscriptions, managed spending | Custodial wallets, exchanges | - - -For full TypeScript, Rust, and program-level examples, see the -[approve and revoke cookbook page](/light-token/cookbook/approve-revoke). - - diff --git a/light-token/payments/verify-recipient-address.mdx b/light-token/payments/verify-recipient-address.mdx index b0bd9ec..8319c6e 100644 --- a/light-token/payments/verify-recipient-address.mdx +++ b/light-token/payments/verify-recipient-address.mdx @@ -1,7 +1,7 @@ --- title: "Verify Address" sidebarTitle: "Verify Recipients Address" -description: "Validate recipient addresses before sending payments to prevent lost funds." +description: "VVerify recipient addresses before sending payments. Address validation prevents sending tokens to invalid or unexpected account types." keywords: ["verify address solana", "address validation light token", "solana address check", "payment safety"] --- @@ -10,8 +10,7 @@ import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; -Verify recipient addresses before sending payments. -Address validation prevents sending tokens to invalid or unexpected account types. +
diff --git a/light-token/payments/wrap-unwrap.mdx b/light-token/payments/wrap-unwrap.mdx index 1f236d5..3897baf 100644 --- a/light-token/payments/wrap-unwrap.mdx +++ b/light-token/payments/wrap-unwrap.mdx @@ -13,7 +13,7 @@ import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; Wrap moves tokens from an SPL or Token 2022 account into a Light Token associated token account. Unwrap moves tokens back. Use wrap/unwrap to interoperate with applications that only support -SPL or Token 2022, such as centralized exchanges. +SPL or Token 2022, such as centralized exchanges or DeFi.
@@ -42,14 +42,6 @@ SPL or Token 2022, such as centralized exchanges. -## When to wrap and unwrap - -| Flow | Use case | -|:-----|:---------| -| **On-ramp** (SPL → Light Token) | User receives USDC from a CEX withdrawal, then wraps to Light Token for cheaper transfers. | -| **Off-ramp** (Light Token → SPL) | User unwraps Light Token USDC to SPL, then deposits to a CEX. | -| **DeFi interop** | Unwrap to use tokens with a protocol that only supports SPL. Wrap back after. | - ## Setup @@ -124,6 +116,7 @@ Find a full code example [here](https://github.com/Lightprotocol/examples-light- Unwrap moves the token balance from a Light Token associated token account to an SPL associated token account. +Use this to compose with applications that do not yet support Light Token. diff --git a/pda/compressed-pdas/how-to-create-nullifier-pdas.mdx b/pda/compressed-pdas/nullifier-pda.mdx similarity index 100% rename from pda/compressed-pdas/how-to-create-nullifier-pdas.mdx rename to pda/compressed-pdas/nullifier-pda.mdx From 0214876e8a1a643d3764a0539c78e97eb0da9234 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Thu, 19 Mar 2026 01:24:11 +0000 Subject: [PATCH 06/19] add payment --- learn/light-token-standard.mdx | 2 +- .../payments/verify-recipient-address.mdx | 2 +- llms.txt | 19 ++++++++++++++----- scripts/generate-llms-txt.js | 6 +++--- skill.md | 2 +- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/learn/light-token-standard.mdx b/learn/light-token-standard.mdx index 437f4a4..033c865 100644 --- a/learn/light-token-standard.mdx +++ b/learn/light-token-standard.mdx @@ -1,5 +1,5 @@ --- -title: Core concepts of the Light Token program (Beta) +title: Core concepts of the Light Token program sidebarTitle: Core Concepts (Light Token Program) description: The Light Token Program is a high performance token program that reduces the cost of account creations by 200x, while being more CU efficient than SPL on hot paths. keywords: ["light token standard on solana", "token 2022 on solana", "token extensions on solana", "spl token on solana", "rent free tokens on solana"] diff --git a/light-token/payments/verify-recipient-address.mdx b/light-token/payments/verify-recipient-address.mdx index 8319c6e..4a4358e 100644 --- a/light-token/payments/verify-recipient-address.mdx +++ b/light-token/payments/verify-recipient-address.mdx @@ -1,7 +1,7 @@ --- title: "Verify Address" sidebarTitle: "Verify Recipients Address" -description: "VVerify recipient addresses before sending payments. Address validation prevents sending tokens to invalid or unexpected account types." +description: "Verify recipient addresses before sending payments. Address validation prevents sending tokens to invalid or unexpected account types." keywords: ["verify address solana", "address validation light token", "solana address check", "payment safety"] --- diff --git a/llms.txt b/llms.txt index bfebd3a..49a392a 100644 --- a/llms.txt +++ b/llms.txt @@ -76,11 +76,21 @@ Comparing creation cost and CU usage: ## For Payments and Wallets - [Payment Flows on Solana with Light Token](https://www.zkcompression.com/light-token/payments/overview.md): Learn how the Light Token API's reduce account creation cost for stablecoin payment infrastructure by 99% with similar developer experience to SPL / Token 2022. -- [Integration Guide for Stablecoin Payments](https://www.zkcompression.com/light-token/payments/integration-guide.md): Guide to integrate light-token APIs for stablecoin payments with comparison to SPL. +- **Send Payments:** [Basic Payment](https://www.zkcompression.com/light-token/payments/basic-payment.md): Send a single token transfer with Light Token APIs for stablecoin payments with comparison to SPL. +- **Send Payments:** [Batch Payments](https://www.zkcompression.com/light-token/payments/batch-payments.md): Send payments to multiple recipients in a single transaction or sequentially. +- **Send Payments:** [Payment with Memo](https://www.zkcompression.com/light-token/payments/payment-with-memo.md): Attach invoice IDs, payment references, or notes to Light Token transfers using Solana's memo program. The memo is recorded in the transaction logs for reconciliation. +- [Receive Payments](https://www.zkcompression.com/light-token/payments/receive-payments.md): Prepare to receive token payments by loading cold accounts and sharing your associated token account address. +- **Verify Payments:** [Verify Payments](https://www.zkcompression.com/light-token/payments/verify-payments.md): Query token balances and transaction history to verify incoming payments. +- **Verify Payments:** [Verify Address](https://www.zkcompression.com/light-token/payments/verify-recipient-address.md): Verify recipient addresses before sending payments. Address validation prevents sending tokens to invalid or unexpected account types. +- [Wrap and Unwrap](https://www.zkcompression.com/light-token/payments/wrap-unwrap.md): Move tokens between SPL / Token 2022 and Light Token accounts for CEX on-ramps, off-ramps, and interoperability. +- **Advanced:** [Spend Permissions via Delegation](https://www.zkcompression.com/light-token/payments/spend-permissions.md): Delegate token spending to a third party with an amount cap. The delegate can transfer tokens on behalf of the owner up to the approved amount, without the owner signing each transaction. +- **Advanced:** [Create Nullifier PDAs](https://www.zkcompression.com/pda/compressed-pdas/nullifier-pda.md): Create rent-free nullifier PDAs to prevent duplicate actions. +- [Production Readiness](https://www.zkcompression.com/light-token/payments/production-readiness.md): Non-exhaustive checklist for deploying Light Token payment flows to production, including RPC infrastructure, error handling, and security. - [Integration Guide for Wallet Applications](https://www.zkcompression.com/light-token/wallets/overview.md): Guide for Wallet Applications to add Light-token support. - [Sign with Privy](https://www.zkcompression.com/light-token/wallets/privy.md): Integrate light-token with Privy embedded wallets for rent-free token accounts and transfers. - [Sign with Wallet Adapter](https://www.zkcompression.com/light-token/wallets/wallet-adapter.md): Integrate light-token with Solana Wallet Adapter for rent-free token accounts and transfers. -- [Sponsor Rent Top-Ups for Users](https://www.zkcompression.com/light-token/wallets/sponsor-top-ups.md): The Light SDK sponsors rent-exemption for Solana accounts and keeps accounts active through periodic top-ups paid by the fee payer. Sponsor top-ups by setting your application as the fee payer to abstract away holding SOL from your users or provide a rent-free experience similar to transaction fee sponsorship. +- [Gasless Transactions](https://www.zkcompression.com/light-token/wallets/gasless-transactions.md): Abstract SOL fees so users never hold SOL. The Light SDK sponsors rent-exemption for Solana accounts and keeps accounts active through periodic top-ups paid by the fee payer. Sponsor top-ups and transaction fees by setting your application as the fee payer. +- [Smart Wallets](https://www.zkcompression.com/light-token/wallets/smart-wallets.md): Send Light Tokens from PDA-based smart wallets. Covers off-curve associated token account creation, instruction-level transfers, and sync and async execution with Squads. ## For DeFi - [Router Integration](https://www.zkcompression.com/light-token/defi/routers.md): Add support for rent-free AMMs on Solana. @@ -113,7 +123,6 @@ Comparing creation cost and CU usage: - [Light PDA](https://www.zkcompression.com/pda/light-pda/overview.md): Create Solana PDA accounts with sponsored rent-exemption and minimal code changes. Use like any Solana PDA, e.g. for DeFi pools, vaults, pool accounts, or other shared state. - **Compressed PDA:** [Overview & Program Template](https://www.zkcompression.com/pda/compressed-pdas/overview.md): Compressed PDAs provide full composability and functionality of accounts at PDAs, without rent-exemption cost per account. Suited for accounts where each user or entity gets their own PDA and state is infrequently accessed. - **Compressed PDA:** [Client Guide](https://www.zkcompression.com/pda/compressed-pdas/guides/client-guide.md): Rust and Typescript client guides with step-by-step implementation and full code examples. -- **Compressed PDA:** [Create Nullifier PDAs](https://www.zkcompression.com/pda/compressed-pdas/how-to-create-nullifier-pdas.md): Create rent-free nullifier PDAs to prevent duplicate actions. - **Compressed PDA > Program Guides:** [Overview](https://www.zkcompression.com/pda/compressed-pdas/guides.md): Overview to guides for Solana programs to create, update, close, reinitialize, and burn permanently compressed accounts. - **Compressed PDA:** [Program Examples](https://www.zkcompression.com/pda/compressed-pdas/program-examples.md): Program example repository for compressed accounts with tests. @@ -125,7 +134,7 @@ Comparing creation cost and CU usage: ## Learn - [Overview of core concepts](https://www.zkcompression.com/learn/overview.md): Learn about Light Token and ZK Compression Core. -- [Core concepts of the Light Token program (Beta)](https://www.zkcompression.com/learn/light-token-standard.md): The Light Token Program is a high performance token program that reduces the cost of account creations by 200x, while being more CU efficient than SPL on hot paths. +- [Core concepts of the Light Token program](https://www.zkcompression.com/learn/light-token-standard.md): The Light Token Program is a high performance token program that reduces the cost of account creations by 200x, while being more CU efficient than SPL on hot paths. - **Core Concepts (ZK Compression):** [High-level System Overview](https://www.zkcompression.com/learn/core-concepts.md): Overview to ZK Compression's Core Concepts. Get a high-level system overview and learn about the compressed account model, lifecycle of a transaction, and considerations. - **Core Concepts (ZK Compression):** [Compressed Account Model](https://www.zkcompression.com/learn/core-concepts/compressed-account-model.md): Overview to compressed accounts and comparison to Solana accounts. - **Core Concepts (ZK Compression):** [Merkle trees and Validity Proofs](https://www.zkcompression.com/learn/core-concepts/merkle-trees-validity-proofs.md): Learn the core concepts of state trees, address trees, and validity proofs for compressed accounts. @@ -160,7 +169,7 @@ Comparing creation cost and CU usage: - [payments-and-wallets](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets): Wallet integrations and payment flows. - [sign-with-privy](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy): Light-token operations signed with Privy wallets. - [sign-with-wallet-adapter](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter): Light-token operations signed with Wallet Adapter. -- [sponsor-rent-top-ups](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sponsor-rent-top-ups): Sponsor rent top-ups by setting your application as the fee payer. +- [gasless-transactions](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions): Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees. - [spl-to-light](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/spl-to-light): Transfer from SPL to Light via TransferInterface. ## OpenAPI Specs diff --git a/scripts/generate-llms-txt.js b/scripts/generate-llms-txt.js index 45da54f..dd6fb59 100644 --- a/scripts/generate-llms-txt.js +++ b/scripts/generate-llms-txt.js @@ -261,7 +261,7 @@ const EXAMPLES_PAYMENTS = [ '- [payments-and-wallets](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets): Wallet integrations and payment flows.', '- [sign-with-privy](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy): Light-token operations signed with Privy wallets.', '- [sign-with-wallet-adapter](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter): Light-token operations signed with Wallet Adapter.', - '- [sponsor-rent-top-ups](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sponsor-rent-top-ups): Sponsor rent top-ups by setting your application as the fee payer.', + '- [gasless-transactions](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions): Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees.', '- [spl-to-light](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/spl-to-light): Transfer from SPL to Light via TransferInterface.', ]; @@ -270,8 +270,8 @@ const EXAMPLES_PAYMENTS = [ const PRIMITIVES_SECTION = ` | Primitive | Use case | Constraints | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | -| Light Token | Most token use cases (Payment Rails, Consumer Apps, DeFi). Rent-free mint and token accounts. More compute-unit efficient on the hot path. | Currently in Beta and on Solana Devnet with mainnet in Q1 2026 | -| Light-PDA | DeFi program state such as AMM pools and vaults. Can be implemented with minimal code changes. | Currently in Beta and on Solana Devnet with mainnet in Q1 2026 | +| Light Token | Most token use cases (Payment Rails, Consumer Apps, DeFi). Rent-free mint and token accounts. More compute-unit efficient on the hot path. | | +| Light-PDA | DeFi program state such as AMM pools and vaults. Can be implemented with minimal code changes. | | | Compressed Token | Only for Airdrops and token distribution. Prefer Light Token for other purposes. Used by Light Token under the hood for rent-free storage of inactive Light Tokens. Supported by Phantom and Backpack. | Do not use for general-purpose token features. Use Light Token instead. | | Compressed PDA | User state and app state, nullifiers (payments and ZK applications), DePIN nodes, and stake accounts. Similar to program-derived addresses without a rent-exempt balance. | Not for shared state, pool accounts, or config accounts. Use Light-PDA instead | diff --git a/skill.md b/skill.md index 4b4c365..d1d6f1c 100644 --- a/skill.md +++ b/skill.md @@ -85,7 +85,7 @@ npx skills add Lightprotocol/skills | For Solana program development with tokens and PDAs, Light is 200x cheaper than SPL/ Solana and has minimal code differences | [light-sdk](https://github.com/Lightprotocol/skills/tree/main/skills/light-sdk) | | For client development with tokens on Solana, Light Token is 200x cheaper than SPL and has minimal changes | [light-token-client](https://github.com/Lightprotocol/skills/tree/main/skills/light-token-client) | | For data pipelines, aggregators, or indexers, real-time account state streaming on Solana with light account hot/cold lifecycle tracking | [data-streaming](https://github.com/Lightprotocol/skills/tree/main/skills/data-streaming) | -| For stablecoin payment flows and wallet integrations on Solana 200x cheaper token accounts | [payments-and-wallets](https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets) | +| For stablecoin payment flows on Solana: send, receive, batch, memo, verify, spend permissions, wrap/unwrap, production readiness | [payments-and-wallets](https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets) | | For token distribution on Solana 5000x cheaper than SPL (rewards, airdrops, depins, ...) | [token-distribution](https://github.com/Lightprotocol/skills/tree/main/skills/token-distribution) | | For custom ZK Solana programs and privacy-preserving applications to prevent double spending | [zk-nullifier](https://github.com/Lightprotocol/skills/tree/main/skills/zk-nullifier) | | For program development on Solana with infrequently accessed state, such as per-user state, DePIN registrations, ... | [solana-compression](https://github.com/Lightprotocol/skills/tree/main/skills/solana-compression) | From 02e26d78521922f18d959d4f171ce8de6f919994 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Thu, 19 Mar 2026 21:27:58 +0000 Subject: [PATCH 07/19] add extnesions --- ai-tools/agent-skills.mdx | 2 +- api-reference/solana-to-light-comparison.mdx | 8 +- docs.json | 24 +- faq.mdx | 29 +- learn/light-token-standard.mdx | 2 +- light-token/cookbook/add-interface-pda.mdx | 46 +++ light-token/cookbook/create-mint.mdx | 38 +-- light-token/cookbook/load-ata.mdx | 2 +- light-token/cookbook/wrap-unwrap.mdx | 4 +- light-token/extensions/close-mint.mdx | 217 ++++++++++++++ .../extensions/confidential-transfer.mdx | 257 ++++++++++++++++ .../extensions/default-account-state.mdx | 219 ++++++++++++++ .../extensions/interest-bearing-tokens.mdx | 221 ++++++++++++++ .../metadata-and-metadata-pointer.mdx | 253 ++++++++++++++++ light-token/extensions/overview.mdx | 88 +++--- light-token/extensions/pausable-mint.mdx | 218 ++++++++++++++ light-token/extensions/permanent-delegate.mdx | 217 ++++++++++++++ .../extensions/token-groups-and-members.mdx | 280 ++++++++++++++++++ light-token/extensions/transfer-fees.mdx | 225 ++++++++++++++ light-token/extensions/transfer-hook.mdx | 222 ++++++++++++++ light-token/payments/basic-payment.mdx | 4 +- light-token/payments/batch-payments.mdx | 4 +- light-token/payments/integration-guide.mdx | 16 +- light-token/payments/overview.mdx | 24 +- light-token/payments/receive-payments.mdx | 2 +- light-token/payments/verify-payments.mdx | 4 +- light-token/payments/wrap-unwrap.mdx | 4 +- light-token/wallets/overview.mdx | 16 +- pda/light-pda/overview.mdx | 2 - resources/legacy-compressed-tokens.mdx | 7 +- resources/terminology.mdx | 4 +- scripts/generate-llms-txt.js | 6 +- skill.md | 4 +- snippets/ai-prompts/defi/defi-anchor.mdx | 4 +- snippets/ai-prompts/extensions/close-mint.mdx | 123 ++++++++ .../extensions/confidential-transfer.mdx | 123 ++++++++ .../extensions/default-account-state.mdx | 123 ++++++++ .../extensions/interest-bearing-tokens.mdx | 117 ++++++++ .../metadata-and-metadata-pointer.mdx | 117 ++++++++ .../ai-prompts/extensions/pausable-mint.mdx | 123 ++++++++ .../extensions/permanent-delegate.mdx | 123 ++++++++ .../extensions/token-groups-and-members.mdx | 123 ++++++++ .../ai-prompts/extensions/transfer-fees.mdx | 123 ++++++++ .../ai-prompts/extensions/transfer-hook.mdx | 123 ++++++++ snippets/ai-prompts/toolkits/payments.mdx | 8 +- snippets/ai-prompts/toolkits/wallets.mdx | 8 +- .../wallets/gasless-transactions.mdx | 4 +- snippets/ai-prompts/wallets/privy.mdx | 4 +- .../ai-prompts/wallets/wallet-adapter.mdx | 4 +- .../native-program/full-example.mdx | 2 +- .../code-snippets/privy/unwrap/nodejs.mdx | 2 +- snippets/code-snippets/privy/unwrap/react.mdx | 4 +- snippets/code-snippets/privy/wrap/react.mdx | 4 +- .../wallet-adapter/unwrap/react.mdx | 4 +- .../wallet-adapter/wrap/react.mdx | 4 +- snippets/extensions-table.mdx | 18 ++ .../light-token-client-examples-table.mdx | 2 +- .../light-token-program-examples-table.mdx | 2 +- snippets/setup/agent-skill-payments.mdx | 2 +- snippets/setup/extensions-setup.mdx | 18 ++ snippets/setup/register-spl-mint.mdx | 2 +- 61 files changed, 3788 insertions(+), 195 deletions(-) create mode 100644 light-token/cookbook/add-interface-pda.mdx create mode 100644 light-token/extensions/close-mint.mdx create mode 100644 light-token/extensions/confidential-transfer.mdx create mode 100644 light-token/extensions/default-account-state.mdx create mode 100644 light-token/extensions/interest-bearing-tokens.mdx create mode 100644 light-token/extensions/metadata-and-metadata-pointer.mdx create mode 100644 light-token/extensions/pausable-mint.mdx create mode 100644 light-token/extensions/permanent-delegate.mdx create mode 100644 light-token/extensions/token-groups-and-members.mdx create mode 100644 light-token/extensions/transfer-fees.mdx create mode 100644 light-token/extensions/transfer-hook.mdx create mode 100644 snippets/ai-prompts/extensions/close-mint.mdx create mode 100644 snippets/ai-prompts/extensions/confidential-transfer.mdx create mode 100644 snippets/ai-prompts/extensions/default-account-state.mdx create mode 100644 snippets/ai-prompts/extensions/interest-bearing-tokens.mdx create mode 100644 snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx create mode 100644 snippets/ai-prompts/extensions/pausable-mint.mdx create mode 100644 snippets/ai-prompts/extensions/permanent-delegate.mdx create mode 100644 snippets/ai-prompts/extensions/token-groups-and-members.mdx create mode 100644 snippets/ai-prompts/extensions/transfer-fees.mdx create mode 100644 snippets/ai-prompts/extensions/transfer-hook.mdx create mode 100644 snippets/extensions-table.mdx create mode 100644 snippets/setup/extensions-setup.mdx diff --git a/ai-tools/agent-skills.mdx b/ai-tools/agent-skills.mdx index 2efb1db..cccabcc 100644 --- a/ai-tools/agent-skills.mdx +++ b/ai-tools/agent-skills.mdx @@ -39,7 +39,7 @@ npx skills add Lightprotocol/skills | Build rent-free Solana programs with Light SDK (Anchor or Pinocchio). Includes router integration. | [light-sdk](https://github.com/Lightprotocol/skills/tree/main/skills/light-sdk) | | Use Light Token client SDKs (TypeScript and Rust) for mints, ATAs, transfers | [light-token-client](https://github.com/Lightprotocol/skills/tree/main/skills/light-token-client) | | Stream account state via Laserstream gRPC | [data-streaming](https://github.com/Lightprotocol/skills/tree/main/skills/data-streaming) | -| Wallets and payment flows with light-token. Includes privy, wallet adapter, mobile wallet adapter signing. Optional nullifier to prevent your onchain instruction from being executed more than once. | [payments-and-wallets](https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets) | +| Skill for payment flows using Light Token APIs for sponsored rent-exemption. | [payments](https://github.com/Lightprotocol/skills/tree/main/skills/payments) | | Airdrops, DePIN, token distribution | [token-distribution](https://github.com/Lightprotocol/skills/tree/main/skills/token-distribution) | | Anti-double-spend nullifiers for Privacy-preserving ZK programs | [zk-nullifier](https://github.com/Lightprotocol/skills/tree/main/skills/zk-nullifier) | | Testing programs and clients on localnet, devnet, mainnet | [testing](https://github.com/Lightprotocol/skills/tree/main/skills/testing) | diff --git a/api-reference/solana-to-light-comparison.mdx b/api-reference/solana-to-light-comparison.mdx index 4b50c61..e532f64 100644 --- a/api-reference/solana-to-light-comparison.mdx +++ b/api-reference/solana-to-light-comparison.mdx @@ -108,7 +108,7 @@ See [JSON RPC Methods](/api-reference/json-rpc-methods/overview). Fetch the parsed state of a light token account, including hot and cold balances. > [Guide](/light-token/payments/integration-guide) | -> [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/get-balance.ts) +> [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-balance.ts) @@ -126,7 +126,7 @@ console.log(account.amount); Fetch merged and deduplicated transaction history across on-chain and compressed transactions. > [Guide](/light-token/payments/integration-guide) | -> [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/get-history.ts) +> [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-history.ts) @@ -650,8 +650,8 @@ For payment flows, `createTransferInterfaceInstructions` returns transferring in one call: > [Guide](/light-token/payments/integration-guide) | -> [Example (instruction)](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/send-instruction.ts) | -> [Example (action)](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/send-action.ts) +> [Example (instruction)](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/send-instruction.ts) | +> [Example (action)](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/send-action.ts) ```typescript import { Transaction } from "@solana/web3.js"; diff --git a/docs.json b/docs.json index a02e52d..c9392bf 100644 --- a/docs.json +++ b/docs.json @@ -39,7 +39,13 @@ { "group": "Cookbook", "pages": [ - "light-token/cookbook/create-mint", + { + "group": "Mint Accounts", + "pages": [ + "light-token/cookbook/create-mint", + "light-token/cookbook/add-interface-pda" + ] + }, "light-token/cookbook/create-ata", "light-token/cookbook/create-token-account", "light-token/cookbook/mint-to", @@ -53,6 +59,22 @@ "light-token/cookbook/burn" ] }, + { + "group": "Extensions", + "pages": [ + "light-token/extensions/overview", + "light-token/extensions/metadata-and-metadata-pointer", + "light-token/extensions/transfer-fees", + "light-token/extensions/transfer-hook", + "light-token/extensions/interest-bearing-tokens", + "light-token/extensions/default-account-state", + "light-token/extensions/permanent-delegate", + "light-token/extensions/close-mint", + "light-token/extensions/token-groups-and-members", + "light-token/extensions/pausable-mint", + "light-token/extensions/confidential-transfer" + ] + }, { "group": "For Stablecoin Payments", "pages": [ diff --git a/faq.mdx b/faq.mdx index 29d646d..e0140b6 100644 --- a/faq.mdx +++ b/faq.mdx @@ -75,9 +75,9 @@ Light token is a high-performance token standard that is functionally equivalent -Yes! Light Token is deployed on devnet. You can start integrating today with our [Quickstart](/light-token/quickstart) and [Toolkits](/light-token/welcome). +Yes! Light Token is live on Solana mainnet. Start integrating with the [Quickstart](/light-token/quickstart) and [Toolkits](/light-token/welcome). -For production on mainnet, use [Compressed Tokens V1](/resources/legacy-compressed-tokens), which are live and supported by leading wallets such as Phantom and Backpack. +For token distribution use cases (airdrops, claims), see [Compressed Tokens](/resources/legacy-compressed-tokens), supported by leading wallets such as Phantom and Backpack. @@ -159,26 +159,11 @@ The account is loaded into hot account state in-flight when someone interacts wi -Extensions are under development. Additional extensions can be requested. - -Coming soon: - -- MetadataPointer -- TokenMetadata -- InterestBearingConfig -- GroupPointer -- GroupMemberPointer -- TokenGroup -- TokenGroupMember -- MintCloseAuthority -- TransferFeeConfig -- DefaultAccountState -- PermanentDelegate -- TransferHook -- Pausable -- ConfidentialTransferMint -- ConfidentialTransferFeeConfig -- ConfidentialMintBurn +Light Token supports 16 Token-2022 extensions, including MetadataPointer, TokenMetadata, TransferFeeConfig, PermanentDelegate, TransferHook, and more. Some extensions have restrictions (e.g., transfer fees must be zero). + + + +Additional extensions can be requested. diff --git a/learn/light-token-standard.mdx b/learn/light-token-standard.mdx index 033c865..002f4c6 100644 --- a/learn/light-token-standard.mdx +++ b/learn/light-token-standard.mdx @@ -79,7 +79,7 @@ Light-mints **uniquely represent a token on Solana and store its global metadata pub struct CompressedMint { pub base: BaseMint, pub metadata: CompressedMintMetadata, - /// Reserved bytes for T22 layout compatibility (padding to reach byte 165) + /// Reserved bytes for Token 2022 layout compatibility (padding to reach byte 165) pub reserved: [u8; 49], /// Account type discriminator at byte 165 (1 = Mint, 2 = Account) pub account_type: u8, diff --git a/light-token/cookbook/add-interface-pda.mdx b/light-token/cookbook/add-interface-pda.mdx new file mode 100644 index 0000000..b0682df --- /dev/null +++ b/light-token/cookbook/add-interface-pda.mdx @@ -0,0 +1,46 @@ +--- +title: Add Interface PDA to Existing SPL / Token 2022 Mints +sidebarTitle: Add Interface PDA to Existing Mints +description: Create an interface PDA for an existing SPL or Token 2022 mint for interoperability with Light Token. Does not require mint authority. +--- + +import TokenPoolActionCode from "/snippets/code-snippets/light-token/create-token-pool/action.mdx"; +import TokenPoolInstructionCode from "/snippets/code-snippets/light-token/create-token-pool/instruction.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + + + + + + + + + + +# Related guides + + + + + + + + diff --git a/light-token/cookbook/create-mint.mdx b/light-token/cookbook/create-mint.mdx index 2cd0192..d223ee1 100644 --- a/light-token/cookbook/create-mint.mdx +++ b/light-token/cookbook/create-mint.mdx @@ -1,7 +1,7 @@ --- title: Create Mint Account with Token Metadata -sidebarTitle: Create Mint Account -description: Program and client guides to create a mint with token metadata. For existing SPL or Token 2022 mints add an interface PDA for interoperability. Includes step-by-step implementation and full code examples. +sidebarTitle: Create Light / SPL / Token 2022 Mint Account +description: Create a Light mint with token metadata, or create SPL and Token 2022 mints with interface PDA for interoperability. keywords: ["create mint account on solana", "rent free mint on solana", "rent free token mints on solana", "spl create mint alternative"] --- @@ -33,8 +33,7 @@ import SplActionCode from "/snippets/code-snippets/light-token/create-spl-mint/a import SplInstructionCode from "/snippets/code-snippets/light-token/create-spl-mint/instruction.mdx"; import T22ActionCode from "/snippets/code-snippets/light-token/create-t22-mint/action.mdx"; import T22InstructionCode from "/snippets/code-snippets/light-token/create-t22-mint/instruction.mdx"; -import TokenPoolActionCode from "/snippets/code-snippets/light-token/create-token-pool/action.mdx"; -import TokenPoolInstructionCode from "/snippets/code-snippets/light-token/create-token-pool/instruction.mdx"; + import RustActionCode from "/snippets/code-snippets/light-token/create-mint/rust-client/action.mdx"; import RustInstructionCode from "/snippets/code-snippets/light-token/create-mint/rust-client/instruction.mdx"; import AnchorProgramCode from "/snippets/code-snippets/light-token/create-mint/anchor-program/full-example.mdx"; @@ -48,7 +47,7 @@ import ProgramCreateMintMacrosAiPrompt from "/snippets/ai-prompts/program-cookbo 1. Mint accounts uniquely represent a token on Solana and store its global metadata. 2. Light mints are on-chain accounts like SPL mints, but the light token program sponsors the rent-exemption cost for you. -3. Add an interface PDA to existing SPL or Token 2022 mints for interoperability with Light Token. The interface PDA holds SPL or Token 2022 tokens when wrapped to Light Token. +3. [Add an interface PDA](/light-token/cookbook/add-interface-pda) to existing SPL or Token 2022 mints for interoperability with Light Token. The interface PDA holds SPL or Token 2022 tokens when wrapped to Light Token. @@ -63,7 +62,7 @@ import ProgramCreateMintMacrosAiPrompt from "/snippets/ai-prompts/program-cookbo `createMintInterface` is a unified interface that dispatches to different mint creation paths based on programId: -- `TOKEN_PROGRAM_ID` or `TOKEN_2022_PROGRAM_ID` → delegates to SPL or T22 `createMint` +- `TOKEN_PROGRAM_ID` or `TOKEN_2022_PROGRAM_ID` → delegates to SPL or Token 2022 `createMint` - Otherwise it defaults to `LIGHT_TOKEN_PROGRAM_ID` → creates a Light Token mint You can use the same interface regardless of mint type. @@ -93,7 +92,7 @@ Compare to SPL: The `mintAuthority` must be a `Signer` for light-mints but can be just a - `PublicKey` for SPL/T22. + `PublicKey` for SPL/Token 2022. @@ -113,24 +112,7 @@ Compare to SPL: -### Add Interface PDA to SPL / Token 2022 mints - - - - -Register an interface PDA for an existing SPL mint for interoperability with Light Token. No mint authority required. - - - - - - - - - - - - +## Create SPL mint with interface PDA Pass `TOKEN_PROGRAM_ID` to create a standard SPL mint with an interface PDA in one transaction for interoperability with Light Token. @@ -143,8 +125,7 @@ Pass `TOKEN_PROGRAM_ID` to create a standard SPL mint with an interface PDA in o - - +## Create Token 2022 mint with interface PDA Pass `TOKEN_2022_PROGRAM_ID` to create a Token-2022 mint with an interface PDA in one transaction for interoperability with Light Token. @@ -157,9 +138,6 @@ Pass `TOKEN_2022_PROGRAM_ID` to create a Token-2022 mint with an interface PDA i - - - diff --git a/light-token/cookbook/load-ata.mdx b/light-token/cookbook/load-ata.mdx index 73fd2f1..8f40f1c 100644 --- a/light-token/cookbook/load-ata.mdx +++ b/light-token/cookbook/load-ata.mdx @@ -13,7 +13,7 @@ import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; 1. `loadAta` unifies tokens from multiple sources to a single ATA: * Compressed tokens (cold Light Tokens) -> Decompresses -> light ATA * SPL balance (if wrap=true) -> Wraps -> light ATA - * T22 balance (if wrap=true) -> Wraps -> light ATA + * Token 2022 balance (if wrap=true) -> Wraps -> light ATA 2. Returns `null` if there's nothing to load (idempotent) diff --git a/light-token/cookbook/wrap-unwrap.mdx b/light-token/cookbook/wrap-unwrap.mdx index a346ccb..0e60179 100644 --- a/light-token/cookbook/wrap-unwrap.mdx +++ b/light-token/cookbook/wrap-unwrap.mdx @@ -19,8 +19,8 @@ import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import WrapUnwrapAiPrompt from "/snippets/ai-prompts/ts-cookbook/wrap-unwrap.mdx"; import RustWrapUnwrapAiPrompt from "/snippets/ai-prompts/rust-cookbook/wrap-unwrap.mdx"; -- **Wrap**: Move tokens from SPL/T22 account → Light Token ATA (hot balance) -- **Unwrap**: Move tokens from Light Token ATA (hot balance) → SPL/T22 account +- **Wrap**: Move tokens from SPL/Token 2022 account → Light Token ATA (hot balance) +- **Unwrap**: Move tokens from Light Token ATA (hot balance) → SPL/Token 2022 account Find the source code: diff --git a/light-token/extensions/close-mint.mdx b/light-token/extensions/close-mint.mdx new file mode 100644 index 0000000..58b0752 --- /dev/null +++ b/light-token/extensions/close-mint.mdx @@ -0,0 +1,217 @@ +--- +title: "Close mint" +sidebarTitle: "Close mint" +description: "Configure the MintCloseAuthority extension to allow closing a mint account and reclaiming rent using Light Token." +keywords: ["close mint light token", "mint close authority solana", "token 2022 close mint"] +--- + +import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import CloseMintAiPrompt from "/snippets/ai-prompts/extensions/close-mint.mdx"; + +A designated authority can close a mint account and reclaim its rent-exempt lamports after all tokens have been burned and the total supply reaches zero. + + +MintCloseAuthority mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) for transfers — compressed transfer instructions are not supported. + + +## Key Concepts + +MintCloseAuthority is configured with one parameter: + +| Parameter | Description | +|-----------|-------------| +| `closeAuthority` | The public key authorized to close the mint account and reclaim its rent-exempt lamports. | + +Standard SPL mints cannot be closed once created, leaving rent-exempt lamports locked permanently. MintCloseAuthority adds a close authority that can reclaim those lamports after the total supply reaches zero. + +## How It Works + +1. A mint authority creates a Token-2022 mint with the MintCloseAuthority extension +2. The close authority is set at initialization +3. All tokens must be burned, reducing the total supply to zero +4. The close authority submits a close instruction to reclaim the mint account's rent + +## Use MintCloseAuthority With Light Token + + + + + + + + + + + +### Create a Token-2022 Mint With Close Authority + + + + +```typescript +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + ExtensionType, + getMintLen, + createInitializeMint2Instruction, + createInitializeMintCloseAuthorityInstruction, +} from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const decimals = 9; + +// Calculate space for mint + MintCloseAuthority extension +const mintLen = getMintLen([ExtensionType.MintCloseAuthority]); +const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + +// Create account +const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, +}); + +// Initialize MintCloseAuthority extension +const initMintCloseAuthorityIx = createInitializeMintCloseAuthorityInstruction( + mintKeypair.publicKey, + payer.publicKey, // close authority + TOKEN_2022_PROGRAM_ID, +); + +// Initialize mint +const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID, +); + +// Register interface PDA with Light Token +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); + +const tx = new Transaction().add( + createAccountIx, + initMintCloseAuthorityIx, + initMintIx, + createSplInterfaceIx +); + +const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, +]); +``` + + + + +```typescript +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { createMintInterface } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const { mint, transactionSignature } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + mintKeypair, + undefined, + TOKEN_2022_PROGRAM_ID +); +``` + + +`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the MintCloseAuthority extension, use the instruction approach shown in the other tab. + + + + + + + + +### Register an Existing Mint + +If you already have a Token-2022 mint with MintCloseAuthority, register it with Light Token. + +```typescript +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); +``` + + + + +### Transfer Tokens + +Transfers work identically to any other Light Token mint. The close authority can reclaim rent only after all tokens are burned. + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + + + + + + + + +## Related Guides + + + + + + + diff --git a/light-token/extensions/confidential-transfer.mdx b/light-token/extensions/confidential-transfer.mdx new file mode 100644 index 0000000..321e215 --- /dev/null +++ b/light-token/extensions/confidential-transfer.mdx @@ -0,0 +1,257 @@ +--- +title: "Confidential transfer" +sidebarTitle: "Confidential transfer" +description: "Configure the ConfidentialTransferMint, ConfidentialTransferFeeConfig, and ConfidentialMintBurn extensions for encrypted token amounts using Light Token." +keywords: ["confidential transfer light token", "confidential transfer solana", "token 2022 confidential transfer"] +--- + +import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import ConfidentialTransferAiPrompt from "/snippets/ai-prompts/extensions/confidential-transfer.mdx"; + +Encrypt token transfer amounts using ElGamal encryption so they are not visible on-chain, while keeping account addresses public and balances auditable by a designated auditor key. + + +Light Token supports confidential transfer extensions in their **initialized-but-disabled state** only. You can create Token-2022 mints with these extensions configured and register them with Light Token, but the confidential transfer features (encrypted amounts, confidential fees, confidential minting/burning) cannot be actively used through Light Token. + + +## Key Concepts + +The confidential transfer family includes three extensions: + +| Extension | Parameters | Light Token restriction | +|-----------|------------|----------------------| +| `ConfidentialTransferMint` | `authority`, `autoApproveNewAccounts`, `auditorElGamalPubkey` | Initialized but **not enabled**. The extension can exist on the mint, but encrypted transfers cannot be performed through Light Token. | +| `ConfidentialTransferFeeConfig` | `authority`, `withdrawWithheldAuthorityElGamalPubkey`, `harvestToMintEnabled`, `withheldAmount` | Fees **must be zero**. The extension can be initialized for compatibility, but confidential fee collection is not supported. | +| `ConfidentialMintBurn` | `confidentialSupply`, `decryptableSupply`, `supplyElGamalPubkey` | Initialized but **not enabled**. The extension can exist on the mint, but encrypted minting and burning cannot be performed through Light Token. | + +## How It Works + +1. A mint authority creates a Token-2022 mint with one or more confidential transfer extensions +2. The extensions are initialized with their configuration parameters (authority, auditor key, auto-approve settings) +3. The extensions remain in an initialized-but-disabled state — no encrypted transfers, fees, or minting/burning occur +4. The mint is registered with Light Token, which validates the extensions are in their disabled state +5. Transfers through Light Token use standard (non-encrypted) amounts + +## Use Confidential Transfer With Light Token + + + + + + + + + + + +### Create a Token-2022 Mint With ConfidentialTransferMint + + + + +```typescript +import { + Keypair, + PublicKey, + SystemProgram, + Transaction, + TransactionInstruction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + ExtensionType, + TOKEN_2022_PROGRAM_ID, + createInitializeMint2Instruction, + getMintLen, +} from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +/** + * Build the InitializeMint instruction for ConfidentialTransferMint. + * + * The @solana/spl-token SDK defines ExtensionType.ConfidentialTransferMint + * but does not yet export a helper for this instruction, so we construct + * it manually using the Token-2022 instruction layout. + */ +function createInitializeConfidentialTransferMintIx( + mint: PublicKey, + authority: PublicKey | null, + autoApproveNewAccounts: boolean, + auditorElGamalPubkey: Uint8Array | null, +): TransactionInstruction { + // TokenInstruction::ConfidentialTransferExtension = 27 + // ConfidentialTransferInstruction::InitializeMint = 0 + const data = Buffer.alloc(2 + 1 + 32 + 1 + 1 + 32); + let offset = 0; + data.writeUInt8(27, offset); offset += 1; // TokenInstruction + data.writeUInt8(0, offset); offset += 1; // InitializeMint sub-instruction + + // authority (COption): 1 byte tag + 32 bytes + if (authority) { + data.writeUInt8(1, offset); offset += 1; + authority.toBuffer().copy(data, offset); offset += 32; + } else { + data.writeUInt8(0, offset); offset += 1; + offset += 32; + } + + // auto_approve_new_accounts: bool (1 byte) + data.writeUInt8(autoApproveNewAccounts ? 1 : 0, offset); offset += 1; + + // auditor_elgamal_pubkey (COption): 1 byte tag + 32 bytes + if (auditorElGamalPubkey) { + data.writeUInt8(1, offset); offset += 1; + Buffer.from(auditorElGamalPubkey).copy(data, offset); + } else { + data.writeUInt8(0, offset); offset += 1; + } + + return new TransactionInstruction({ + keys: [{ pubkey: mint, isSigner: false, isWritable: true }], + programId: TOKEN_2022_PROGRAM_ID, + data, + }); +} + +const mintKeypair = Keypair.generate(); +const decimals = 9; + +// Calculate space including ConfidentialTransferMint extension +const mintLen = getMintLen([ExtensionType.ConfidentialTransferMint]); +const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + +// Create account +const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, +}); + +// Initialize ConfidentialTransferMint extension (must come before mint init) +// auto_approve_new_accounts: false — extension is initialized but not enabled +// auditor_elgamal_pubkey: null — no auditor configured +const initConfidentialTransferIx = createInitializeConfidentialTransferMintIx( + mintKeypair.publicKey, + payer.publicKey, // authority + false, // auto_approve_new_accounts (not enabled) + null, // auditor_elgamal_pubkey +); + +// Initialize mint +const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID, +); + +// Register interface PDA with Light Token +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); + +const tx = new Transaction().add( + createAccountIx, + initConfidentialTransferIx, + initMintIx, + createSplInterfaceIx, +); + +const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, +]); +``` + + + + +```typescript +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { createMintInterface } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const { mint, transactionSignature } = await createMintInterface( + rpc, payer, payer, null, 9, mintKeypair, undefined, TOKEN_2022_PROGRAM_ID +); +``` + + +`createMintInterface` creates a basic Token-2022 mint with an interface PDA. To include the ConfidentialTransferMint extension, use the instruction approach shown in the other tab. + + + + + + + + +### Register an Existing Mint + +If you already have a Token-2022 mint with confidential transfer extensions in their disabled state, register it with Light Token. + +```typescript +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); +``` + + + + +### Transfer Tokens + +Transfers work identically to any other Light Token mint. The SDK handles loading cold balances automatically. Because confidential transfer is initialized but not enabled, all amounts remain unencrypted. + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, payer.publicKey, mint, amount, owner.publicKey, recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + + + + + + + + +## Related Guides + + + + + + + diff --git a/light-token/extensions/default-account-state.mdx b/light-token/extensions/default-account-state.mdx new file mode 100644 index 0000000..65ed1f8 --- /dev/null +++ b/light-token/extensions/default-account-state.mdx @@ -0,0 +1,219 @@ +--- +title: "Default account state" +sidebarTitle: "Default account state" +description: "Configure the DefaultAccountState extension to set the initial state for newly created token accounts using Light Token." +keywords: ["default account state light token", "default account state solana", "token 2022 default account state"] +--- + +import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import DefaultAccountStateAiPrompt from "/snippets/ai-prompts/extensions/default-account-state.mdx"; + +Every new token account created under a mint starts in a specified state, such as frozen, requiring the freeze authority to thaw accounts before holders can transact. + + +DefaultAccountState mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) for transfers — compressed transfer instructions are not supported. + + +## Key Concepts + +DefaultAccountState is configured with two parameters: + +| Parameter | Description | +|-----------|-------------| +| `state` | The initial `AccountState` for new token accounts. Set to `Frozen` to require approval before transacting. | +| `freezeAuthority` | Authority that can thaw frozen accounts and update the default state. **Required when the default state is `Frozen`.** | + +When a new token account is created for this mint, the token program automatically sets its state to the configured default. If the default is `Frozen`, the account cannot send or receive tokens until the freeze authority thaws it. + +## How It Works + +1. A mint authority creates a Token-2022 mint with the DefaultAccountState extension +2. The default state is set at initialization (typically `Frozen`) +3. Every new token account for that mint starts in the configured state +4. The freeze authority thaws individual accounts after verifying the holder + +## Use DefaultAccountState With Light Token + + + + + + + + + + + +### Create a Token-2022 Mint With Default Account State + + + + +```typescript +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + ExtensionType, + getMintLen, + createInitializeMint2Instruction, + createInitializeDefaultAccountStateInstruction, + AccountState, +} from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const decimals = 9; + +// Calculate space for mint + DefaultAccountState extension +const mintLen = getMintLen([ExtensionType.DefaultAccountState]); +const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + +// Create account +const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, +}); + +// Initialize DefaultAccountState extension +const initDefaultAccountStateIx = createInitializeDefaultAccountStateInstruction( + mintKeypair.publicKey, + AccountState.Frozen, + TOKEN_2022_PROGRAM_ID, +); + +// Initialize mint +const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + payer.publicKey, // freeze authority (required for frozen default state) + TOKEN_2022_PROGRAM_ID, +); + +// Register interface PDA with Light Token +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); + +const tx = new Transaction().add( + createAccountIx, + initDefaultAccountStateIx, + initMintIx, + createSplInterfaceIx +); + +const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, +]); +``` + + + + +```typescript +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { createMintInterface } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const { mint, transactionSignature } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + mintKeypair, + undefined, + TOKEN_2022_PROGRAM_ID +); +``` + + +`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the DefaultAccountState extension, use the instruction approach shown in the other tab. + + + + + + + + +### Register an Existing Mint + +If you already have a Token-2022 mint with DefaultAccountState, register it with Light Token. + +```typescript +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); +``` + + + + +### Transfer Tokens + +Transfers work identically to any other Light Token mint. Accounts must be thawed by the freeze authority before they can send or receive tokens. + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + + + + + + + + +## Related Guides + + + + + + + diff --git a/light-token/extensions/interest-bearing-tokens.mdx b/light-token/extensions/interest-bearing-tokens.mdx new file mode 100644 index 0000000..3612fc4 --- /dev/null +++ b/light-token/extensions/interest-bearing-tokens.mdx @@ -0,0 +1,221 @@ +--- +title: "Interest bearing tokens" +sidebarTitle: "Interest bearing tokens" +description: "Configure the InterestBearingConfig extension to display UI-adjusted balances that accrue interest over time using Light Token." +keywords: ["interest bearing light token", "interest bearing solana", "token 2022 interest bearing"] +--- + +import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import InterestBearingTokensAiPrompt from "/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx"; + +## Key Concepts + +A configurable interest rate on the mint lets clients display a UI-adjusted balance that grows over time, while the on-chain token balance remains unchanged. + +InterestBearingConfig is configured with these parameters: + +| Parameter | Description | +|-----------|-------------| +| `rateAuthority` | Account authorized to update the interest rate after initialization. | +| `currentRate` | Active interest rate in basis points (e.g., 500 = 5%). | +| `initializationTimestamp` | Network timestamp recorded when the extension is created. | +| `lastUpdateTimestamp` | Network timestamp of the most recent rate change, used as the reference for interest calculations. | +| `preUpdateAverageRate` | Previous rate value preserved when the rate authority updates `currentRate`. | + +## How It Works + +1. A mint authority creates a Token-2022 mint with the InterestBearingConfig extension +2. The rate authority and initial interest rate are set at initialization +3. The token program records the network timestamp as the initialization reference +4. On every balance query, clients compute accrued interest from the stored rate and elapsed time +5. The rate authority can update the rate at any time; the previous rate is preserved in `preUpdateAverageRate` + +This extension is fully supported by Light Token without restrictions. + +## Use InterestBearingConfig With Light Token + + + + + + + + + + + +### Create a Token-2022 Mint With Interest Bearing Config + + + + +```typescript +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + getMintLen, + createInitializeMint2Instruction, + ExtensionType, + createInitializeInterestBearingMintInstruction, +} from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const decimals = 9; +const rate = 500; // 5% interest rate in basis points + +// Calculate space for mint + InterestBearingConfig extension +const mintLen = getMintLen([ExtensionType.InterestBearingConfig]); +const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + +// Create account +const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, +}); + +// Initialize InterestBearingConfig +const initInterestBearingIx = + createInitializeInterestBearingMintInstruction( + mintKeypair.publicKey, + payer.publicKey, // rate authority + rate, + TOKEN_2022_PROGRAM_ID + ); + +// Initialize mint +const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, + null, + TOKEN_2022_PROGRAM_ID +); + +// Register interface PDA with Light Token +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); + +const tx = new Transaction().add( + createAccountIx, + initInterestBearingIx, + initMintIx, + createSplInterfaceIx +); + +const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, +]); +``` + + + + +```typescript +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { createMintInterface } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const { mint, transactionSignature } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + mintKeypair, + undefined, + TOKEN_2022_PROGRAM_ID +); +``` + + +`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the InterestBearingConfig extension, use the instruction approach shown in the other tab. + + + + + + + + +### Register an Existing Mint + +If you already have a Token-2022 mint with InterestBearingConfig, register it with Light Token. + +```typescript +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); +``` + + + + +### Transfer Tokens + +Transfers work identically to any other Light Token mint. The interest bearing config does not affect transfer behavior; it only changes how clients display the balance. + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + + + + + + + + +## Related Guides + + + + + + + diff --git a/light-token/extensions/metadata-and-metadata-pointer.mdx b/light-token/extensions/metadata-and-metadata-pointer.mdx new file mode 100644 index 0000000..fc2d6c0 --- /dev/null +++ b/light-token/extensions/metadata-and-metadata-pointer.mdx @@ -0,0 +1,253 @@ +--- +title: "Metadata and metadata pointer" +sidebarTitle: "Metadata and metadata pointer" +description: "Configure the MetadataPointer and TokenMetadata extensions to store token name, symbol, and URI on a Token 2022 mint using Light Token." +keywords: ["metadata pointer light token", "token metadata solana", "token 2022 metadata"] +--- + +import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import MetadataAndMetadataPointerAiPrompt from "/snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx"; + +MetadataPointer tells clients where to find a mint's metadata. TokenMetadata removes the need for a separate metadata account. + +## Key Concepts + +MetadataPointer and TokenMetadata are configured together with these parameters: + +| Parameter | Description | +|-----------|-------------| +| `authority` | Account authorized to update the metadata pointer address. | +| `metadataAddress` | Account where metadata is stored. Set to the mint itself to keep metadata on-chain in a single account. | +| `updateAuthority` | Account that can modify token metadata fields after initialization. | +| `name` | Human-readable token name (e.g., "Example Token"). | +| `symbol` | Short token symbol (e.g., "EXT"). | +| `uri` | URL pointing to an external JSON file with extended metadata. | +| `additionalMetadata` | Key-value pairs for custom descriptive fields. | + +When the MetadataPointer points to the mint itself, TokenMetadata stores name, symbol, URI, and additional fields directly in the mint account data. This produces a self-describing token in a single account. + +## How It Works + +1. A mint authority creates a Token-2022 mint with both the MetadataPointer and TokenMetadata extensions +2. MetadataPointer is initialized with the mint address as the metadata location +3. The mint is initialized with decimals and authorities +4. TokenMetadata is initialized with name, symbol, and URI on the mint account +5. Clients read the MetadataPointer, find the mint address, and deserialize the TokenMetadata directly from it + +Both extensions work without restrictions in Light Token. + +## Use MetadataPointer and TokenMetadata With Light Token + + + + + + + + + + + +### Create a Token-2022 Mint With Metadata + + + + +```typescript +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + getMintLen, + createInitializeMint2Instruction, + ExtensionType, +} from "@solana/spl-token"; +import { + createInitializeMetadataPointerInstruction, +} from "@solana/spl-token"; +import { + createInitializeInstruction as createInitializeTokenMetadataInstruction, + pack, + TokenMetadata, +} from "@solana/spl-token-metadata"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const decimals = 9; + +const metadata: TokenMetadata = { + mint: mintKeypair.publicKey, + name: "Example Token", + symbol: "EXT", + uri: "https://example.com/metadata.json", + additionalMetadata: [], +}; + +// Calculate space for mint + MetadataPointer extension +const mintLen = getMintLen([ExtensionType.MetadataPointer]); +const metadataLen = pack(metadata).length; +const totalLen = mintLen + metadataLen; +const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(totalLen); + +// Create account +const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, +}); + +// Initialize MetadataPointer (points to the mint itself) +const initMetadataPointerIx = createInitializeMetadataPointerInstruction( + mintKeypair.publicKey, + payer.publicKey, + mintKeypair.publicKey, // metadata address = mint itself + TOKEN_2022_PROGRAM_ID +); + +// Initialize mint +const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, + null, + TOKEN_2022_PROGRAM_ID +); + +// Initialize TokenMetadata on the mint +const initTokenMetadataIx = createInitializeTokenMetadataInstruction({ + programId: TOKEN_2022_PROGRAM_ID, + mint: mintKeypair.publicKey, + metadata: mintKeypair.publicKey, + mintAuthority: payer.publicKey, + name: metadata.name, + symbol: metadata.symbol, + uri: metadata.uri, + updateAuthority: payer.publicKey, +}); + +// Register interface PDA with Light Token +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); + +const tx = new Transaction().add( + createAccountIx, + initMetadataPointerIx, + initMintIx, + initTokenMetadataIx, + createSplInterfaceIx +); + +const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, +]); +``` + + + + +```typescript +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { createMintInterface } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const { mint, transactionSignature } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + mintKeypair, + undefined, + TOKEN_2022_PROGRAM_ID +); +``` + + +`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include MetadataPointer and TokenMetadata extensions, use the instruction approach shown in the other tab. + + + + + + + + +### Register an Existing Mint + +If you already have a Token-2022 mint with metadata, register it with Light Token. + +```typescript +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); +``` + + + + +### Transfer Tokens + +Transfers work identically to any other Light Token mint. The metadata extensions do not affect transfer behavior. + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + + + + + + + + +## Related Guides + + + + + + + diff --git a/light-token/extensions/overview.mdx b/light-token/extensions/overview.mdx index 6f939c0..e87780e 100644 --- a/light-token/extensions/overview.mdx +++ b/light-token/extensions/overview.mdx @@ -1,49 +1,45 @@ --- -title: Token Extensions -description: "Token extensions supported by light-token. Includes restricted extensions: supported with constraints (e.g. zero fees, nil transfer hook)." -hidden: true +title: "Token extensions" +sidebarTitle: "Overview" +description: "Most Token 2022 extensions are supported by Light Token to add features through extra instructions to a token mint or token account." +keywords: ["token 2022 extensions light token", "token extensions solana", "metadata pointer light token", "transfer fee config light token", "confidential transfers light token"] --- -Light-token supports wrapping and holding balances from Token-2022 mints. The following T22 extensions are supported. Some are **restricted**: the extension is supported only when configured in a specific way (e.g. zero fees, transfer hook disabled). - -### Supported with restrictions - -| Extension | Restriction | -|-----------|-------------| -| TransferFeeConfig | Fees must be zero | -| ConfidentialTransferFeeConfig | Fees must be zero | -| DefaultAccountState | Any state allowed | -| TransferHook | `program_id` must be nil (hook disabled) | -| ConfidentialTransferMint | Initialized but not enabled | -| ConfidentialMintBurn | Initialized but not enabled | - -### Full supported extensions list - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Extension NameRestriction / noteslight-tokenCompressed Token
MetadataPointer-YesYes
TokenMetadata-YesYes
InterestBearingConfig-YesYes
GroupPointer-YesYes
GroupMemberPointer-YesYes
TokenGroup-YesYes
TokenGroupMember-YesYes
MintCloseAuthority-Yes-
TransferFeeConfigFees must be zeroYes-
DefaultAccountStateAny state allowedYes-
PermanentDelegate-Yes-
TransferHookprogram_id must be nilYes-
Pausable-Yes-
ConfidentialTransferMintInitialized but not enabledYes-
ConfidentialTransferFeeConfigFees must be zeroYes-
ConfidentialMintBurnInitialized but not enabledYes-
\ No newline at end of file +import SupportFooter from "/snippets/support-footer.mdx"; + +## How extensions work with Light Token + +1. **Create** a Token-2022 mint with one or more extensions +2. **Register** an interface PDA to hold balances from that mint in Light Token accounts +3. **Use** the same Light Token APIs (`transferInterface`, `wrap`, `unwrap`) as any other token + +Each extension adds specific state that's generally initialized during mint or token account creation. +When initializing either account, you can enable specific extensions simultaneously for different functionality. +Most extensions can't be added after an account is initialized. + +## Supported extensions + +| Extension | Restriction | Description | +|-----------|-------------|-------------| +| [MetadataPointer](/light-token/extensions/metadata-and-metadata-pointer) | - | Points a mint to the account that stores its metadata. | +| [TokenMetadata](/light-token/extensions/metadata-and-metadata-pointer) | - | Stores token name, symbol, and URI directly on the mint. | +| [TransferFeeConfig](/light-token/extensions/transfer-fees) | Fees must be zero | Withholds a percentage of each transfer as a fee. | +| [TransferHook](/light-token/extensions/transfer-hook) | `program_id` must be nil | Invokes a custom program on every transfer via CPI. | +| [InterestBearingConfig](/light-token/extensions/interest-bearing-tokens) | - | Displays a UI-adjusted balance that accrues interest over time. | +| [DefaultAccountState](/light-token/extensions/default-account-state) | No compressed transfer | Sets the initial state (e.g., frozen) for newly created token accounts. | +| [PermanentDelegate](/light-token/extensions/permanent-delegate) | No compressed transfer | Grants an authority unrestricted transfer and burn rights over all accounts for the mint. | +| [MintCloseAuthority](/light-token/extensions/close-mint) | No compressed transfer | Allows a designated authority to close a mint account. | +| [GroupPointer](/light-token/extensions/token-groups-and-members) | - | Points a mint to the account that stores group configuration. | +| [GroupMemberPointer](/light-token/extensions/token-groups-and-members) | - | Points a mint to the account that stores group member configuration. | +| [TokenGroup](/light-token/extensions/token-groups-and-members) | - | Stores group configuration directly on the mint (e.g., NFT collections). | +| [TokenGroupMember](/light-token/extensions/token-groups-and-members) | - | Stores group member configuration directly on the mint. | +| [Pausable](/light-token/extensions/pausable-mint) | No compressed transfer | Allows an authority to pause all minting, burning, and transfers. | +| [ConfidentialTransferMint](/light-token/extensions/confidential-transfer) | Initialized but not enabled | Configures auditor keys for confidential (encrypted) transfers. | +| [ConfidentialTransferFeeConfig](/light-token/extensions/confidential-transfer) | Fees must be zero | Encrypts withheld transfer fees under an auditor's public key. | +| [ConfidentialMintBurn](/light-token/extensions/confidential-transfer) | Initialized but not enabled | Allows minting and burning of tokens with encrypted amounts. | + +## Not supported + +The following Token-2022 extensions are not supported by Light Token: Scaled UI Amount, Non-Transferable Tokens, Memo Transfer, Immutable Owner, CPI Guard. + + diff --git a/light-token/extensions/pausable-mint.mdx b/light-token/extensions/pausable-mint.mdx new file mode 100644 index 0000000..137ad9e --- /dev/null +++ b/light-token/extensions/pausable-mint.mdx @@ -0,0 +1,218 @@ +--- +title: "Pausable mint" +sidebarTitle: "Pausable mint" +description: "Configure the Pausable extension to pause and resume all minting, burning, and transfers for a Token-2022 mint using Light Token." +keywords: ["pausable light token", "pausable solana", "token 2022 pausable"] +--- + +import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import PausableMintAiPrompt from "/snippets/ai-prompts/extensions/pausable-mint.mdx"; + +When paused, all minting, burning, and transfers are blocked until the authority resumes the mint. + + +Pausable mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) for transfers — compressed transfer instructions are not supported. + + +## Key Concepts + +Pausable is configured with two parameters: + +| Parameter | Description | +|-----------|-------------| +| `authority` | The public key authorized to pause and resume the mint. | +| `paused` | Boolean flag indicating the current pause state. Initialized as `false`. | + +When paused, the Token-2022 program rejects all transfers, mints, and burns for the token. The pause authority can resume operations at any time. + +## How It Works + +1. A mint authority creates a Token-2022 mint with the Pausable extension +2. The pause authority is set at initialization, with the mint starting in an unpaused state +3. The pause authority can call `pause` to halt all minting, burning, and transfers +4. The pause authority can call `resume` to re-enable operations + +## Use Pausable With Light Token + + + + + + + + + + + +### Create a Token-2022 Mint With Pausable + + + + +```typescript +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + ExtensionType, + getMintLen, + createInitializeMint2Instruction, + createInitializePausableConfigInstruction, +} from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const decimals = 9; + +// Calculate space for mint + Pausable extension +const mintLen = getMintLen([ExtensionType.PausableConfig]); +const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + +// Create account +const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, +}); + +// Initialize Pausable extension +const initPausableIx = createInitializePausableConfigInstruction( + mintKeypair.publicKey, + payer.publicKey, // pause authority + TOKEN_2022_PROGRAM_ID, +); + +// Initialize mint +const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID, +); + +// Register interface PDA with Light Token +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); + +const tx = new Transaction().add( + createAccountIx, + initPausableIx, + initMintIx, + createSplInterfaceIx +); + +const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, +]); +``` + + + + +```typescript +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { createMintInterface } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const { mint, transactionSignature } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + mintKeypair, + undefined, + TOKEN_2022_PROGRAM_ID +); +``` + + +`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the Pausable extension, use the instruction approach shown in the other tab. + + + + + + + + +### Register an Existing Mint + +If you already have a Token-2022 mint with Pausable, register it with Light Token. + +```typescript +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); +``` + + + + +### Transfer Tokens + +Transfers work identically to any other Light Token mint, as long as the mint is not currently paused. + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + + + + + + + + +## Related Guides + + + + + + + diff --git a/light-token/extensions/permanent-delegate.mdx b/light-token/extensions/permanent-delegate.mdx new file mode 100644 index 0000000..56fa4e0 --- /dev/null +++ b/light-token/extensions/permanent-delegate.mdx @@ -0,0 +1,217 @@ +--- +title: "Permanent delegate" +sidebarTitle: "Permanent delegate" +description: "Configure the PermanentDelegate extension to grant irrevocable transfer and burn authority over all token accounts using Light Token." +keywords: ["permanent delegate light token", "permanent delegate solana", "token 2022 permanent delegate"] +--- + +import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import PermanentDelegateAiPrompt from "/snippets/ai-prompts/extensions/permanent-delegate.mdx"; + +A designated authority gains irrevocable transfer and burn rights over every token account for a mint, set once at initialization and enforced permanently. + + +PermanentDelegate mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) for transfers — compressed transfer instructions are not supported. + + +## Key Concepts + +PermanentDelegate is configured with one parameter: + +| Parameter | Description | +|-----------|-------------| +| `delegate` | The public key granted permanent, irrevocable transfer and burn authority over all token accounts for this mint. | + +Unlike standard delegates set per token account, the permanent delegate operates at the mint level. Token account owners cannot revoke this authority. Only the current permanent delegate can reassign the role to a new account. + +## How It Works + +1. A mint authority creates a Token-2022 mint with the PermanentDelegate extension +2. The delegate address is set at initialization and cannot be removed +3. The permanent delegate can transfer or burn tokens from any token account for this mint without owner approval +4. The delegate authority persists for the lifetime of the mint + +## Use PermanentDelegate With Light Token + + + + + + + + + + + +### Create a Token-2022 Mint With Permanent Delegate + + + + +```typescript +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + ExtensionType, + getMintLen, + createInitializeMint2Instruction, + createInitializePermanentDelegateInstruction, +} from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const decimals = 9; + +// Calculate space for mint + PermanentDelegate extension +const mintLen = getMintLen([ExtensionType.PermanentDelegate]); +const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + +// Create account +const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, +}); + +// Initialize PermanentDelegate extension +const initPermanentDelegateIx = createInitializePermanentDelegateInstruction( + mintKeypair.publicKey, + payer.publicKey, // permanent delegate authority + TOKEN_2022_PROGRAM_ID, +); + +// Initialize mint +const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID, +); + +// Register interface PDA with Light Token +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); + +const tx = new Transaction().add( + createAccountIx, + initPermanentDelegateIx, + initMintIx, + createSplInterfaceIx +); + +const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, +]); +``` + + + + +```typescript +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { createMintInterface } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const { mint, transactionSignature } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + mintKeypair, + undefined, + TOKEN_2022_PROGRAM_ID +); +``` + + +`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the PermanentDelegate extension, use the instruction approach shown in the other tab. + + + + + + + + +### Register an Existing Mint + +If you already have a Token-2022 mint with PermanentDelegate, register it with Light Token. + +```typescript +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); +``` + + + + +### Transfer Tokens + +Transfers work identically to any other Light Token mint. The permanent delegate retains authority to transfer or burn tokens from any account. + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + + + + + + + + +## Related Guides + + + + + + + diff --git a/light-token/extensions/token-groups-and-members.mdx b/light-token/extensions/token-groups-and-members.mdx new file mode 100644 index 0000000..a4757d5 --- /dev/null +++ b/light-token/extensions/token-groups-and-members.mdx @@ -0,0 +1,280 @@ +--- +title: "Token groups and members" +sidebarTitle: "Token groups and members" +description: "Configure the GroupPointer, TokenGroup, GroupMemberPointer, and TokenGroupMember extensions to organize tokens into collections using Light Token." +keywords: ["token groups light token", "token groups solana", "token 2022 token groups", "nft collections solana"] +--- + +import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import TokenGroupsAndMembersAiPrompt from "/snippets/ai-prompts/extensions/token-groups-and-members.mdx"; + +Organize tokens into hierarchical groups such as NFT collections by linking a group mint to one or more member mints through on-chain pointer and data extensions. + +## Key Concepts + +Token groups use four related extensions that work in pairs: + +| Extension | Parameters | Description | +|-----------|------------|-------------| +| `GroupPointer` | `authority`, `groupAddress` | Designates a mint as a group mint by pointing to an account that stores group configuration. Typically points to the mint itself. | +| `TokenGroup` | `updateAuthority`, `mint`, `size`, `maxSize` | Stores the group metadata (update authority, current member count, maximum size) directly on the mint account. | +| `GroupMemberPointer` | `authority`, `memberAddress` | Designates a mint as a member mint by pointing to an account that stores membership data. Typically points to the mint itself. | +| `TokenGroupMember` | `mint`, `group`, `memberNumber` | Stores the membership data (parent group address, sequential member number) directly on the mint account. | + +## How It Works + +1. A mint authority creates a **group mint** with the GroupPointer and TokenGroup extensions, setting a max member count and update authority +2. The GroupPointer references the account that stores group data — typically the mint itself +3. For each member, a separate **member mint** is created with the GroupMemberPointer and TokenGroupMember extensions +4. The TokenGroupMember extension links the member mint to the parent group and assigns a sequential member number +5. Both group and member mints are registered with Light Token for rent-free compressed accounts + +## Use Token Groups With Light Token + + + + + + + + + + + +### Create Group Mint + +Create a Token-2022 mint with the GroupPointer and TokenGroup extensions. + + + + +```typescript +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + ExtensionType, + getMintLen, + createInitializeMint2Instruction, + createInitializeGroupPointerInstruction, + createInitializeGroupInstruction, +} from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const groupMintKeypair = Keypair.generate(); +const decimals = 0; + +// Calculate space including GroupPointer and TokenGroup extensions +const mintLen = getMintLen([ExtensionType.GroupPointer, ExtensionType.TokenGroup]); +const rentExemptBalance = await rpc.getMinimumBalanceForRentExemption(mintLen); + +// Create the mint account +const createMintAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: groupMintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, +}); + +// Initialize GroupPointer (points to the mint itself) +const initGroupPointerIx = createInitializeGroupPointerInstruction( + groupMintKeypair.publicKey, + payer.publicKey, // authority + groupMintKeypair.publicKey, // group address (self-referencing) + TOKEN_2022_PROGRAM_ID, +); + +// Initialize the mint +const initMintIx = createInitializeMint2Instruction( + groupMintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID, +); + +// Initialize the TokenGroup data on the mint +const initGroupIx = createInitializeGroupInstruction({ + group: groupMintKeypair.publicKey, + maxSize: 100, + mint: groupMintKeypair.publicKey, + mintAuthority: payer.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + updateAuthority: payer.publicKey, +}); + +const tx = new Transaction().add( + createMintAccountIx, + initGroupPointerIx, + initMintIx, + initGroupIx, +); + +const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + groupMintKeypair, +]); +``` + + + + +```typescript +import { createMintInterface } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const { mint, transactionSignature } = await createMintInterface( + rpc, payer, payer, null, 0, groupMintKeypair, undefined, TOKEN_2022_PROGRAM_ID +); +``` + + +`createMintInterface` creates and registers a standard Token-2022 mint. To add the GroupPointer and TokenGroup extensions, use the instruction approach in the other tab. + + + + + + + + +### Create Member Mint + +Create a member mint with the GroupMemberPointer and TokenGroupMember extensions, linking it to the group mint. + +```typescript +import { + createInitializeGroupMemberPointerInstruction, + createInitializeMemberInstruction, +} from "@solana/spl-token"; + +const memberMintKeypair = Keypair.generate(); + +// Calculate space including GroupMemberPointer and TokenGroupMember extensions +const memberMintLen = getMintLen([ + ExtensionType.GroupMemberPointer, + ExtensionType.TokenGroupMember, +]); +const memberRentExemptBalance = await rpc.getMinimumBalanceForRentExemption(memberMintLen); + +// Create the member mint account +const createMemberMintIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: memberRentExemptBalance, + newAccountPubkey: memberMintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: memberMintLen, +}); + +// Initialize GroupMemberPointer (points to the member mint itself) +const initMemberPointerIx = createInitializeGroupMemberPointerInstruction( + memberMintKeypair.publicKey, + payer.publicKey, // authority + memberMintKeypair.publicKey, // member address (self-referencing) + TOKEN_2022_PROGRAM_ID, +); + +// Initialize the member mint +const initMemberMintIx = createInitializeMint2Instruction( + memberMintKeypair.publicKey, + 0, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID, +); + +// Initialize the TokenGroupMember data on the member mint +const initMemberIx = createInitializeMemberInstruction({ + group: groupMintKeypair.publicKey, + groupUpdateAuthority: payer.publicKey, + member: memberMintKeypair.publicKey, + memberMint: memberMintKeypair.publicKey, + memberMintAuthority: payer.publicKey, + programId: TOKEN_2022_PROGRAM_ID, +}); + +const memberTx = new Transaction().add( + createMemberMintIx, + initMemberPointerIx, + initMemberMintIx, + initMemberIx, +); + +await sendAndConfirmTransaction(rpc, memberTx, [payer, memberMintKeypair]); +``` + + + + +### Register Both Mints With Light Token + +Register both the group mint and member mint with Light Token to enable rent-free compressed accounts. + +```typescript +// Register group mint +const registerGroupIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: groupMintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); + +// Register member mint +const registerMemberIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: memberMintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); + +const registerTx = new Transaction().add(registerGroupIx, registerMemberIx); +await sendAndConfirmTransaction(rpc, registerTx, [payer]); +``` + + + + +### Transfer Tokens + +Once mints are registered, transfers work identically to any other Light Token mint. + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, payer.publicKey, mint, amount, owner.publicKey, recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + + + + + + + + +## Related Guides + + + + + + + diff --git a/light-token/extensions/transfer-fees.mdx b/light-token/extensions/transfer-fees.mdx new file mode 100644 index 0000000..d917a02 --- /dev/null +++ b/light-token/extensions/transfer-fees.mdx @@ -0,0 +1,225 @@ +--- +title: "Transfer fees" +sidebarTitle: "Transfer fees" +description: "Configure the TransferFeeConfig extension for automatic fee collection on every token transfer using Light Token." +keywords: ["transfer fees light token", "transfer fees solana", "token 2022 transfer fees"] +--- + +import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import TransferFeesAiPrompt from "/snippets/ai-prompts/extensions/transfer-fees.mdx"; + +## Key Concepts + +Fees are expressed in basis points and accumulate in recipient token accounts. A designated withdraw authority can collect the accumulated fees. + +Transfer fees are configured with four parameters: + +| Parameter | Description | +|-----------|-------------| +| `transferFeeBasisPoints` | Fee percentage in basis points (100 = 1%). **Must be zero for Light Token.** | +| `maximumFee` | Upper limit on the fee charged per transfer, in token base units. **Must be zero for Light Token.** | +| `transferFeeConfigAuthority` | Authority that can modify fee settings. | +| `withdrawWithheldAuthority` | Authority that can collect accumulated fees from recipient accounts. | + +During a transfer, the token program calculates the fee as a percentage of the transfer amount (capped by `maximumFee`) +and withholds it in the recipient's token account. With Light Token, both values are zero, so no fees are collected. + +## How It Works + +1. A mint authority creates a Token-2022 mint with the TransferFeeConfig extension +2. The fee basis points and maximum fee are set at initialization +3. On every `transfer_checked` call, the token program withholds the fee from the transferred amount +4. Fees accumulate in recipient token accounts and can be harvested to the mint, then withdrawn by the withdraw authority + + +Light Token requires the transfer fee to be set to **zero basis points** and the maximum fee to **zero**. +You can initialize the extension for compatibility with existing Token-2022 mints, but non-zero fees are not supported. Registration fails if fees are non-zero. + + +## Use TransferFeeConfig With Light Token + + + + + + + + + + + +### Create a Token-2022 Mint With Transfer Fees + + + + +```typescript +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + getMintLen, + createInitializeMint2Instruction, + ExtensionType, + createInitializeTransferFeeConfigInstruction, +} from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const decimals = 9; + +// Calculate space for mint + TransferFeeConfig extension +const mintLen = getMintLen([ExtensionType.TransferFeeConfig]); +const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + +// Create account +const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, +}); + +// Initialize TransferFeeConfig with zero fees +const initTransferFeeIx = createInitializeTransferFeeConfigInstruction( + mintKeypair.publicKey, + payer.publicKey, // transfer fee config authority + payer.publicKey, // withdraw withheld authority + 0, // fee basis points (must be zero) + BigInt(0), // maximum fee (must be zero) + TOKEN_2022_PROGRAM_ID +); + +// Initialize mint +const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, + null, + TOKEN_2022_PROGRAM_ID +); + +// Register interface PDA with Light Token +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); + +const tx = new Transaction().add( + createAccountIx, + initTransferFeeIx, + initMintIx, + createSplInterfaceIx +); + +const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, +]); +``` + + + + +```typescript +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { createMintInterface } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const { mint, transactionSignature } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + mintKeypair, + undefined, + TOKEN_2022_PROGRAM_ID +); +``` + + +`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the TransferFeeConfig extension, use the instruction approach shown in the other tab. + + + + + + + + +### Register an Existing Mint + +If you already have a Token-2022 mint with a zero-fee TransferFeeConfig, register it with Light Token. + +```typescript +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); +``` + + + + +### Transfer Tokens + +Transfers work identically to any other Light Token mint. Because the fee is zero, no fees are withheld. + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + + + + + + + + +## Related Guides + + + + + + + diff --git a/light-token/extensions/transfer-hook.mdx b/light-token/extensions/transfer-hook.mdx new file mode 100644 index 0000000..b22687c --- /dev/null +++ b/light-token/extensions/transfer-hook.mdx @@ -0,0 +1,222 @@ +--- +title: "Transfer hook" +sidebarTitle: "Transfer hook" +description: "Configure the TransferHook extension to attach a custom program callback to every token transfer using Light Token." +keywords: ["transfer hook light token", "transfer hook solana", "token 2022 transfer hook"] +--- + +import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; +import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import TransferHookAiPrompt from "/snippets/ai-prompts/extensions/transfer-hook.mdx"; + + +## Key Concepts + +A program address stored on the mint is invoked via CPI on every token transfer to execute custom logic +such as transfer restrictions, royalty enforcement, or event emission. + +TransferHook is configured with two parameters: + +| Parameter | Description | +|-----------|-------------| +| `authority` | Account that can update the transfer hook program address after initialization. | +| `programId` | Address of the program invoked via CPI on every transfer. **Must be `PublicKey.default` (nil) for Light Token.** | + + +## How It Works + +1. A mint authority creates a Token-2022 mint with the TransferHook extension +2. The hook program address is set at initialization (must be nil for Light Token) +3. On every `transfer_checked` call, the token program invokes the hook program via CPI +4. All accounts from the initial transfer are passed as read-only to the hook program +5. If the hook instruction fails, the entire token transfer reverts + + +Light Token requires the TransferHook `program_id` to be set to `PublicKey.default` (all zeros). You can initialize the extension for compatibility, but active hooks are not supported. Registration fails if the `program_id` points to a real program. + + +## Use TransferHook With Light Token + + + + + + + + + + + +### Create a Token-2022 Mint With Transfer Hook + + + + +```typescript +import { + Keypair, + PublicKey, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + getMintLen, + createInitializeMint2Instruction, + ExtensionType, + createInitializeTransferHookInstruction, +} from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const decimals = 9; + +// Calculate space for mint + TransferHook extension +const mintLen = getMintLen([ExtensionType.TransferHook]); +const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + +// Create account +const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, +}); + +// Initialize TransferHook with nil program_id (hook disabled) +const initTransferHookIx = createInitializeTransferHookInstruction( + mintKeypair.publicKey, + payer.publicKey, // authority + PublicKey.default, // program_id must be nil + TOKEN_2022_PROGRAM_ID +); + +// Initialize mint +const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, + null, + TOKEN_2022_PROGRAM_ID +); + +// Register interface PDA with Light Token +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); + +const tx = new Transaction().add( + createAccountIx, + initTransferHookIx, + initMintIx, + createSplInterfaceIx +); + +const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, +]); +``` + + + + +```typescript +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { createMintInterface } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const rpc = createRpc(RPC_ENDPOINT); + +const mintKeypair = Keypair.generate(); +const { mint, transactionSignature } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + mintKeypair, + undefined, + TOKEN_2022_PROGRAM_ID +); +``` + + +`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the TransferHook extension, use the instruction approach shown in the other tab. + + + + + + + + +### Register an Existing Mint + +If you already have a Token-2022 mint with TransferHook set to a nil `program_id`, register it with Light Token. + +```typescript +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; + +const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, +}); +``` + + + + +### Transfer Tokens + +Transfers work identically to any other Light Token mint. Because the hook is disabled, no CPI is invoked during transfers. + +```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} +``` + + + + + + + + + + + +## Related Guides + + + + + + + diff --git a/light-token/payments/basic-payment.mdx b/light-token/payments/basic-payment.mdx index 4d5a0e0..9c80bf9 100644 --- a/light-token/payments/basic-payment.mdx +++ b/light-token/payments/basic-payment.mdx @@ -55,8 +55,8 @@ const rpc = createRpc(RPC_ENDPOINT); Find full runnable code examples: -[instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send-instruction.ts) | -[action](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send-action.ts). +[instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/send-instruction.ts) | +[action](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/send-action.ts). ## Send a payment diff --git a/light-token/payments/batch-payments.mdx b/light-token/payments/batch-payments.mdx index b5dcbb1..0045c12 100644 --- a/light-token/payments/batch-payments.mdx +++ b/light-token/payments/batch-payments.mdx @@ -46,8 +46,8 @@ const rpc = createRpc(RPC_ENDPOINT); Find full code examples: -[single transaction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/batch-send-single-tx.ts) | -[sequential](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/batch-send.ts). +[single transaction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/batch-send-single-tx.ts) | +[sequential](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/batch-send.ts). ## Send to multiple recipients in one transaction diff --git a/light-token/payments/integration-guide.mdx b/light-token/payments/integration-guide.mdx index e761a80..b217aa3 100644 --- a/light-token/payments/integration-guide.mdx +++ b/light-token/payments/integration-guide.mdx @@ -65,7 +65,7 @@ import SupportFooter from "/snippets/support-footer.mdx"; Find full runnable code examples - [here](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets). + [here](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments). @@ -78,7 +78,7 @@ import SupportFooter from "/snippets/support-footer.mdx"; Snippets below assume `rpc`, `payer`, `mint`, `owner`, `recipient`, and `amount` are defined. -See the [full examples](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets) for runnable setup. +See the [full examples](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments) for runnable setup. ```typescript import { createRpc } from "@lightprotocol/stateless.js"; @@ -101,7 +101,7 @@ const rpc = createRpc(RPC_ENDPOINT); ## Receive Payments -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/receive.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/receive/receive.ts). Load creates the associated token account (ATA) if needed and loads any compressed state into it. Share the ATA address with the sender. @@ -188,7 +188,7 @@ const ata = await getOrCreateAssociatedTokenAccount( ## Send Payments -Find a full code example: [instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/send-instruction.ts) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/send-action.ts). +Find a full code example: [instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/send-instruction.ts) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/send-action.ts). @@ -332,7 +332,7 @@ await transfer(connection, payer, sourceAta, destinationAta, owner, amount); ## Show Balance -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/get-balance.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-balance.ts). ```typescript @@ -362,7 +362,7 @@ console.log(account.amount); ## Transaction History -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/get-history.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-history.ts). ```typescript @@ -388,7 +388,7 @@ const signatures = await connection.getSignaturesForAddress(ata); Wrap tokens from SPL/Token-2022 accounts to light-token ATA. -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/wrap.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/wrap.ts). @@ -448,7 +448,7 @@ Unwrap moves the token balance from a light-token account to a SPL-token account Use this to compose with applications that do not yet support light-token. -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/unwrap.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/unwrap.ts). diff --git a/light-token/payments/overview.mdx b/light-token/payments/overview.mdx index 20da49b..3a15bce 100644 --- a/light-token/payments/overview.mdx +++ b/light-token/payments/overview.mdx @@ -20,6 +20,7 @@ import { } from "/snippets/code-samples/code-compare-snippets.jsx"; import SupportFooter from "/snippets/support-footer.mdx"; import RentSponsorship from "/snippets/rent-sponsorship-explained.mdx"; +import ExtensionsTable from "/snippets/extensions-table.mdx"; Payment flows on Solana include five core concepts: @@ -69,27 +70,12 @@ extra instructions. -| Extension | Description | -|-----------|-------------| -| MetadataPointer | Points a mint to the account that stores its metadata. | -| TokenMetadata | Stores token name, symbol, and URI directly on the mint. | -| InterestBearingConfig | Displays a UI-adjusted balance that accrues interest over time. | -| GroupPointer | Points a mint to the account that stores group configuration. | -| GroupMemberPointer | Points a mint to the account that stores group member configuration. | -| TokenGroup | Stores group configuration directly on the mint (e.g., NFT collections). | -| TokenGroupMember | Stores group member configuration directly on the mint. | -| MintCloseAuthority | Allows a designated authority to close a mint account. | -| TransferFeeConfig | Withholds a percentage of each transfer as a fee. | -| DefaultAccountState | Sets the initial state (e.g., frozen) for newly created token accounts. | -| PermanentDelegate | Grants an authority unrestricted transfer and burn rights over all accounts for the mint. | -| TransferHook | Invokes a custom program on every transfer via CPI. | -| Pausable | Allows an authority to pause all minting, burning, and transfers. | -| ConfidentialTransferMint | Configures auditor keys for confidential (encrypted) transfers. | -| ConfidentialTransferFeeConfig | Encrypts withheld transfer fees under an auditor's public key. | -| ConfidentialMintBurn | Allows minting and burning of tokens with encrypted amounts. | + + + -Learn more on extensions here: [Extensions](https://solana.com/docs/tokens/extensions). +Learn more about Token-2022 extensions: [Extensions](https://solana.com/docs/tokens/extensions). diff --git a/light-token/payments/receive-payments.mdx b/light-token/payments/receive-payments.mdx index da5c3d0..35e9db1 100644 --- a/light-token/payments/receive-payments.mdx +++ b/light-token/payments/receive-payments.mdx @@ -51,7 +51,7 @@ const ata = getAssociatedTokenAddressInterface(mint, recipient); ## Load the associated token account -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/receive.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/receive/receive.ts). diff --git a/light-token/payments/verify-payments.mdx b/light-token/payments/verify-payments.mdx index 4a5a2cf..049d7ce 100644 --- a/light-token/payments/verify-payments.mdx +++ b/light-token/payments/verify-payments.mdx @@ -50,7 +50,7 @@ const rpc = createRpc(RPC_ENDPOINT); ## Query balance -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/get-balance.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-balance.ts). ```typescript @@ -80,7 +80,7 @@ console.log(account.amount); ## Transaction history -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/get-history.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-history.ts). Query all transactions for an owner across both on-chain and compressed state: diff --git a/light-token/payments/wrap-unwrap.mdx b/light-token/payments/wrap-unwrap.mdx index 3897baf..8941411 100644 --- a/light-token/payments/wrap-unwrap.mdx +++ b/light-token/payments/wrap-unwrap.mdx @@ -55,7 +55,7 @@ const rpc = createRpc(RPC_ENDPOINT); ## Wrap from SPL -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/wrap.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/wrap.ts). @@ -112,7 +112,7 @@ await wrap(rpc, payer, splAta, tokenAta, owner, mint, amount); ## Unwrap to SPL -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/unwrap.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/unwrap.ts). Unwrap moves the token balance from a Light Token associated token account to an SPL associated token account. diff --git a/light-token/wallets/overview.mdx b/light-token/wallets/overview.mdx index e1d56c5..5f87cff 100644 --- a/light-token/wallets/overview.mdx +++ b/light-token/wallets/overview.mdx @@ -64,7 +64,7 @@ import SupportFooter from "/snippets/support-footer.mdx"; Find full runnable code examples - [here](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets). + [here](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments). @@ -77,7 +77,7 @@ import SupportFooter from "/snippets/support-footer.mdx"; Snippets below assume `rpc`, `payer`, `mint`, `owner`, `recipient`, and `amount` are defined. -See the [full examples](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets) for runnable setup. +See the [full examples](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments) for runnable setup. ```typescript import { createRpc } from "@lightprotocol/stateless.js"; @@ -108,7 +108,7 @@ loop handles the rare multi-transaction case automatically. ## Receive Payments -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/receive.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/receive/receive.ts). Load creates the associated token account (ATA) if needed and loads any compressed state into it. Share the ATA address with the sender. @@ -187,7 +187,7 @@ const ata = await getOrCreateAssociatedTokenAccount( ## Send Payments -Find a full code example: [instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/send-instruction.ts) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/send-action.ts). +Find a full code example: [instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/send-instruction.ts) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/send-action.ts). @@ -276,7 +276,7 @@ await transfer(connection, payer, sourceAta, destinationAta, owner, amount); ## Show Balance -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/get-balance.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-balance.ts). ```typescript @@ -306,7 +306,7 @@ console.log(account.amount); ## Transaction History -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/get-history.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-history.ts). ```typescript @@ -332,7 +332,7 @@ const signatures = await connection.getSignaturesForAddress(ata); Wrap tokens from SPL/Token-2022 accounts to light-token ATA. -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/wrap.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/wrap.ts). @@ -392,7 +392,7 @@ Unwrap moves the token balance from a light-token account to a SPL-token account Use this to compose with applications that do not yet support light-token. -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/unwrap.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/unwrap.ts). diff --git a/pda/light-pda/overview.mdx b/pda/light-pda/overview.mdx index 66df2ea..cc37cda 100644 --- a/pda/light-pda/overview.mdx +++ b/pda/light-pda/overview.mdx @@ -204,8 +204,6 @@ depending on number and type of accounts being initialized or loaded. --- -API is in Beta and subject to change. - Questions or need hands-on support? [Telegram](https://t.me/swen_light) | [email](mailto:support@lightprotocol.com) | [Discord](https://discord.com/invite/7cJ8BhAXhu) diff --git a/resources/legacy-compressed-tokens.mdx b/resources/legacy-compressed-tokens.mdx index cb06ea3..827eb3e 100644 --- a/resources/legacy-compressed-tokens.mdx +++ b/resources/legacy-compressed-tokens.mdx @@ -15,10 +15,9 @@ import AgentSkillAirdrop from "/snippets/setup/agent-skill-airdrop.mdx"; -**Note: The new [Light Token Program Beta](/light-token/welcome)** is live on Solana Devnet with mainnet expected in Q1 2026. -We recommend to use Light Token for most purposes except airdrops and other forms of token distribution. -The SDK for compressed tokens can still be used once Light Token is on Solana Mainnet. -For production use today, use Compressed Tokens, which are on Solana Mainnet. +The [Light Token Program](/light-token/welcome) is live on Solana mainnet. +Use Light Token for most purposes except airdrops and other forms of token distribution. +The compressed token SDK remains supported for token distribution use cases. | Creation | Solana | Compressed | diff --git a/resources/terminology.mdx b/resources/terminology.mdx index b8cd42d..b6b7472 100644 --- a/resources/terminology.mdx +++ b/resources/terminology.mdx @@ -39,7 +39,7 @@ Skills for compressed PDAs and more are in development. | Build rent-free Solana programs with Light SDK (Anchor or Pinocchio). Includes router integration. | [light-sdk](https://github.com/Lightprotocol/skills/tree/main/skills/light-sdk) | | Use Light Token client SDKs (TypeScript and Rust) for mints, ATAs, transfers | [light-token-client](https://github.com/Lightprotocol/skills/tree/main/skills/light-token-client) | | Stream account state via Laserstream gRPC | [data-streaming](https://github.com/Lightprotocol/skills/tree/main/skills/data-streaming) | -| Wallets and payment flows with Light Token. Optional nullifier to prevent your on-chain instruction from being executed more than once. | [payments-and-wallets](https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets) | +| Skill for payment flows using Light Token APIs for sponsored rent-exemption. | [payments](https://github.com/Lightprotocol/skills/tree/main/skills/payments) | | Airdrops, DePIN, token distribution | [token-distribution](https://github.com/Lightprotocol/skills/tree/main/skills/token-distribution) | | Anti-double-spend nullifiers for privacy-preserving ZK programs | [zk-nullifier](https://github.com/Lightprotocol/skills/tree/main/skills/zk-nullifier) | | Testing programs and clients on localnet, devnet, mainnet | [testing](https://github.com/Lightprotocol/skills/tree/main/skills/testing) | @@ -301,7 +301,7 @@ The documentation provides two implementations with rent-free PDA accounts: | **Rust SDK** | [light-nullifier-program](https://crates.io/crates/light-nullifier-program) | | **TypeScript SDK** | [@lightprotocol/nullifier-program](https://www.npmjs.com/package/@lightprotocol/nullifier-program) | -> [Docs](/pda/compressed-pdas/how-to-create-nullifier-pdas) | [Skill](https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets) | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/actions/create_nullifier.rs) +> [Docs](/pda/compressed-pdas/how-to-create-nullifier-pdas) | [Skill](https://github.com/Lightprotocol/skills/tree/main/skills/payments) | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/actions/create_nullifier.rs) **ZK nullifier** — For ZK or privacy-preserving programs on Solana to prevent double-spending. Can be integrated with minimal code changes. diff --git a/scripts/generate-llms-txt.js b/scripts/generate-llms-txt.js index dd6fb59..20cab20 100644 --- a/scripts/generate-llms-txt.js +++ b/scripts/generate-llms-txt.js @@ -139,8 +139,8 @@ function buildAiTools(anchor) { 'For data pipelines, aggregators, or indexers, real-time account state streaming on Solana with light account hot/cold lifecycle tracking', ], [ - 'payments-and-wallets', - 'For stablecoin payment flows and wallet integrations on Solana.', + 'payments', + 'Skill for payment flows using Light Token APIs for sponsored rent-exemption.', ], [ 'token-distribution', @@ -258,7 +258,7 @@ const EXAMPLES_DEFI = [ ]; const EXAMPLES_PAYMENTS = [ - '- [payments-and-wallets](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets): Wallet integrations and payment flows.', + '- [payments](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments): Wallet integrations and payment flows.', '- [sign-with-privy](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy): Light-token operations signed with Privy wallets.', '- [sign-with-wallet-adapter](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter): Light-token operations signed with Wallet Adapter.', '- [gasless-transactions](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions): Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees.', diff --git a/skill.md b/skill.md index d1d6f1c..2727700 100644 --- a/skill.md +++ b/skill.md @@ -85,7 +85,7 @@ npx skills add Lightprotocol/skills | For Solana program development with tokens and PDAs, Light is 200x cheaper than SPL/ Solana and has minimal code differences | [light-sdk](https://github.com/Lightprotocol/skills/tree/main/skills/light-sdk) | | For client development with tokens on Solana, Light Token is 200x cheaper than SPL and has minimal changes | [light-token-client](https://github.com/Lightprotocol/skills/tree/main/skills/light-token-client) | | For data pipelines, aggregators, or indexers, real-time account state streaming on Solana with light account hot/cold lifecycle tracking | [data-streaming](https://github.com/Lightprotocol/skills/tree/main/skills/data-streaming) | -| For stablecoin payment flows on Solana: send, receive, batch, memo, verify, spend permissions, wrap/unwrap, production readiness | [payments-and-wallets](https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets) | +| Skill for payment flows using Light Token APIs for sponsored rent-exemption. | [payments](https://github.com/Lightprotocol/skills/tree/main/skills/payments) | | For token distribution on Solana 5000x cheaper than SPL (rewards, airdrops, depins, ...) | [token-distribution](https://github.com/Lightprotocol/skills/tree/main/skills/token-distribution) | | For custom ZK Solana programs and privacy-preserving applications to prevent double spending | [zk-nullifier](https://github.com/Lightprotocol/skills/tree/main/skills/zk-nullifier) | | For program development on Solana with infrequently accessed state, such as per-user state, DePIN registrations, ... | [solana-compression](https://github.com/Lightprotocol/skills/tree/main/skills/solana-compression) | @@ -175,7 +175,7 @@ Use rent-free PDAs for: user state, app state, nullifiers for payments, DePIN no | | Description | |---------|-------------| -| [Payments and Wallets](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets) | All you need for wallet integrations and payment flows. Minimal API differences to SPL. | +| [Payments](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments) | All you need for wallet integrations and payment flows. Minimal API differences to SPL. | | [Streaming Tokens](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/streaming-tokens/) | Stream mint events using Laserstream | | [Sign with Privy](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy/) | Light-token operations signed with Privy wallets (Node.js + React) | | [Gasless Transactions](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions/) | Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees. | diff --git a/snippets/ai-prompts/defi/defi-anchor.mdx b/snippets/ai-prompts/defi/defi-anchor.mdx index e4b7343..6209f4d 100644 --- a/snippets/ai-prompts/defi/defi-anchor.mdx +++ b/snippets/ai-prompts/defi/defi-anchor.mdx @@ -87,7 +87,7 @@ Violations are bugs. All generated code must satisfy these constraints. - Constructor takes 9 args: \`(amount, decimals, source, destination, authority, fee_payer, light_token_cpi_authority, mint, system_program)\` - Use \`Option\` for SPL interface PDA accounts - Conditionally call \`.with_spl_interface(...)\` when \`spl_interface_pda.is_some()\` -- This enables cross-standard transfers (SPL/T22 source to Light destination) +- This enables cross-standard transfers (SPL/Token 2022 source to Light destination) **Authority pattern:** - Single authority PDA owns all vaults: \`seeds = [AUTHORITY_SEED], bump\` @@ -196,7 +196,7 @@ Violations are bugs. All generated code must satisfy these constraints. - Constructor takes 9 args: `(amount, decimals, source, destination, authority, fee_payer, light_token_cpi_authority, mint, system_program)` - Use `Option` for SPL interface PDA accounts - Conditionally call `.with_spl_interface(...)` when `spl_interface_pda.is_some()` -- This enables cross-standard transfers (SPL/T22 source to Light destination) +- This enables cross-standard transfers (SPL/Token 2022 source to Light destination) **Authority pattern:** - Single authority PDA owns all vaults: `seeds = [AUTHORITY_SEED], bump` diff --git a/snippets/ai-prompts/extensions/close-mint.mdx b/snippets/ai-prompts/extensions/close-mint.mdx new file mode 100644 index 0000000..098eb24 --- /dev/null +++ b/snippets/ai-prompts/extensions/close-mint.mdx @@ -0,0 +1,123 @@ + +{`--- +description: Create a Token-2022 mint with MintCloseAuthority and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with MintCloseAuthority and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/close-mint +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Restriction: compression_only accounts required + +SPL equivalent: createInitializeMintCloseAuthorityInstruction() + createMint() +Light Token: createInitializeMintCloseAuthorityInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep \`@solana/spl-token|Connection|Keypair|MintCloseAuthority|TOKEN_2022\` across src/ +- Glob \`**/*.ts\` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with close authority +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with close authority, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Note: mint can only be closed when total supply is zero (all tokens burned) +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` +- Create T22 mint: getMintLen([ExtensionType.MintCloseAuthority]) → SystemProgram.createAccount → createInitializeMintCloseAuthorityInstruction(closeAuthority) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash \`tsc --noEmit\` +- Bash run existing test suite if present +- Confirm close authority address is set correctly +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work`} + + +```text +--- +description: Create a Token-2022 mint with MintCloseAuthority and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with MintCloseAuthority and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/close-mint +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Restriction: compression_only accounts required + +SPL equivalent: createInitializeMintCloseAuthorityInstruction() + createMint() +Light Token: createInitializeMintCloseAuthorityInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep `@solana/spl-token|Connection|Keypair|MintCloseAuthority|TOKEN_2022` across src/ +- Glob `**/*.ts` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with close authority +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with close authority, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Note: mint can only be closed when total supply is zero (all tokens burned) +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` +- Create T22 mint: getMintLen([ExtensionType.MintCloseAuthority]) → SystemProgram.createAccount → createInitializeMintCloseAuthorityInstruction(closeAuthority) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash `tsc --noEmit` +- Bash run existing test suite if present +- Confirm close authority address is set correctly +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work +``` diff --git a/snippets/ai-prompts/extensions/confidential-transfer.mdx b/snippets/ai-prompts/extensions/confidential-transfer.mdx new file mode 100644 index 0000000..5254423 --- /dev/null +++ b/snippets/ai-prompts/extensions/confidential-transfer.mdx @@ -0,0 +1,123 @@ + +{`--- +description: Create a Token-2022 mint with ConfidentialTransferMint and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with ConfidentialTransferMint and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/confidential-transfer +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Restriction: initialized but NOT enabled + +SPL equivalent: createInitializeConfidentialTransferMintInstruction() (or custom builder) +Light Token: createInitializeConfidentialTransferMintInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep \`@solana/spl-token|Connection|Keypair|ConfidentialTransfer|TOKEN_2022\` across src/ +- Glob \`**/*.ts\` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with confidential transfer +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with confidential transfer, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Ensure extension is initialized but NOT enabled — Light Token does not support active confidential transfers +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` +- Create T22 mint: getMintLen([ExtensionType.ConfidentialTransferMint]) → SystemProgram.createAccount → initialize ConfidentialTransferMint (custom instruction builder) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash \`tsc --noEmit\` +- Bash run existing test suite if present +- Confirm extension is initialized but not enabled +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work`} + + +```text +--- +description: Create a Token-2022 mint with ConfidentialTransferMint and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with ConfidentialTransferMint and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/confidential-transfer +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Restriction: initialized but NOT enabled + +SPL equivalent: createInitializeConfidentialTransferMintInstruction() (or custom builder) +Light Token: createInitializeConfidentialTransferMintInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep `@solana/spl-token|Connection|Keypair|ConfidentialTransfer|TOKEN_2022` across src/ +- Glob `**/*.ts` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with confidential transfer +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with confidential transfer, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Ensure extension is initialized but NOT enabled — Light Token does not support active confidential transfers +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` +- Create T22 mint: getMintLen([ExtensionType.ConfidentialTransferMint]) → SystemProgram.createAccount → initialize ConfidentialTransferMint (custom instruction builder) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash `tsc --noEmit` +- Bash run existing test suite if present +- Confirm extension is initialized but not enabled +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work +``` diff --git a/snippets/ai-prompts/extensions/default-account-state.mdx b/snippets/ai-prompts/extensions/default-account-state.mdx new file mode 100644 index 0000000..7667cf1 --- /dev/null +++ b/snippets/ai-prompts/extensions/default-account-state.mdx @@ -0,0 +1,123 @@ + +{`--- +description: Create a Token-2022 mint with DefaultAccountState and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with DefaultAccountState and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/default-account-state +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Restriction: compression_only accounts required + +SPL equivalent: createInitializeDefaultAccountStateInstruction() + createMint() +Light Token: createInitializeDefaultAccountStateInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep \`@solana/spl-token|Connection|Keypair|DefaultAccountState|TOKEN_2022\` across src/ +- Glob \`**/*.ts\` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with default account state +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with default account state, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Ensure a freeze authority is set (required when default state is Frozen) +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` +- Create T22 mint: getMintLen([ExtensionType.DefaultAccountState]) → SystemProgram.createAccount → createInitializeDefaultAccountStateInstruction(AccountState.Frozen) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash \`tsc --noEmit\` +- Bash run existing test suite if present +- Confirm freeze authority is set in initialization code +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work`} + + +```text +--- +description: Create a Token-2022 mint with DefaultAccountState and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with DefaultAccountState and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/default-account-state +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Restriction: compression_only accounts required + +SPL equivalent: createInitializeDefaultAccountStateInstruction() + createMint() +Light Token: createInitializeDefaultAccountStateInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep `@solana/spl-token|Connection|Keypair|DefaultAccountState|TOKEN_2022` across src/ +- Glob `**/*.ts` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with default account state +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with default account state, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Ensure a freeze authority is set (required when default state is Frozen) +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` +- Create T22 mint: getMintLen([ExtensionType.DefaultAccountState]) → SystemProgram.createAccount → createInitializeDefaultAccountStateInstruction(AccountState.Frozen) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash `tsc --noEmit` +- Bash run existing test suite if present +- Confirm freeze authority is set in initialization code +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work +``` diff --git a/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx b/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx new file mode 100644 index 0000000..3d7d5cc --- /dev/null +++ b/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx @@ -0,0 +1,117 @@ + +{`--- +description: Create a Token-2022 mint with InterestBearingConfig and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with InterestBearingConfig and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/interest-bearing-tokens +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token + +SPL equivalent: createInitializeInterestBearingMintInstruction() +Light Token: createInitializeInterestBearingMintInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep \`@solana/spl-token|Connection|Keypair|InterestBearing|TOKEN_2022\` across src/ +- Glob \`**/*.ts\` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with interest bearing +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with interest bearing, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` +- Create T22 mint: getMintLen([ExtensionType.InterestBearingConfig]) → SystemProgram.createAccount → createInitializeInterestBearingMintInstruction → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash \`tsc --noEmit\` +- Bash run existing test suite if present +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work`} + + +```text +--- +description: Create a Token-2022 mint with InterestBearingConfig and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with InterestBearingConfig and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/interest-bearing-tokens +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token + +SPL equivalent: createInitializeInterestBearingMintInstruction() +Light Token: createInitializeInterestBearingMintInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep `@solana/spl-token|Connection|Keypair|InterestBearing|TOKEN_2022` across src/ +- Glob `**/*.ts` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with interest bearing +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with interest bearing, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` +- Create T22 mint: getMintLen([ExtensionType.InterestBearingConfig]) → SystemProgram.createAccount → createInitializeInterestBearingMintInstruction → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash `tsc --noEmit` +- Bash run existing test suite if present +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work +``` diff --git a/snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx b/snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx new file mode 100644 index 0000000..3282b3d --- /dev/null +++ b/snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx @@ -0,0 +1,117 @@ + +{`--- +description: Create a Token-2022 mint with MetadataPointer and TokenMetadata and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with MetadataPointer and TokenMetadata and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/metadata-and-metadata-pointer +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token, @solana/spl-token-metadata + +SPL equivalent: createInitializeMetadataPointerInstruction() + createInitializeTokenMetadataInstruction() +Light Token: createInitializeMetadataPointerInstruction() + createInitializeTokenMetadataInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep \`@solana/spl-token|Connection|Keypair|MetadataPointer|TOKEN_2022\` across src/ +- Glob \`**/*.ts\` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with metadata extension +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with metadata, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token @solana/spl-token-metadata\` +- Create T22 mint: getMintLen([ExtensionType.MetadataPointer]) → SystemProgram.createAccount → createInitializeMetadataPointerInstruction → createInitializeMint2Instruction → createInitializeTokenMetadataInstruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash \`tsc --noEmit\` +- Bash run existing test suite if present +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work`} + + +```text +--- +description: Create a Token-2022 mint with MetadataPointer and TokenMetadata and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with MetadataPointer and TokenMetadata and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/metadata-and-metadata-pointer +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token, @solana/spl-token-metadata + +SPL equivalent: createInitializeMetadataPointerInstruction() + createInitializeTokenMetadataInstruction() +Light Token: createInitializeMetadataPointerInstruction() + createInitializeTokenMetadataInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep `@solana/spl-token|Connection|Keypair|MetadataPointer|TOKEN_2022` across src/ +- Glob `**/*.ts` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with metadata extension +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with metadata, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token @solana/spl-token-metadata` +- Create T22 mint: getMintLen([ExtensionType.MetadataPointer]) → SystemProgram.createAccount → createInitializeMetadataPointerInstruction → createInitializeMint2Instruction → createInitializeTokenMetadataInstruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash `tsc --noEmit` +- Bash run existing test suite if present +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work +``` diff --git a/snippets/ai-prompts/extensions/pausable-mint.mdx b/snippets/ai-prompts/extensions/pausable-mint.mdx new file mode 100644 index 0000000..0cc0acc --- /dev/null +++ b/snippets/ai-prompts/extensions/pausable-mint.mdx @@ -0,0 +1,123 @@ + +{`--- +description: Create a Token-2022 mint with Pausable and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with Pausable and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/pausable-mint +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Restriction: compression_only accounts required + +SPL equivalent: createInitializePausableInstruction() + createMint() +Light Token: createInitializePausableInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep \`@solana/spl-token|Connection|Keypair|Pausable|TOKEN_2022\` across src/ +- Glob \`**/*.ts\` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with pausable +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with pausable, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Note: when paused, all minting, burning, and transfers are rejected until resumed +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` +- Create T22 mint: getMintLen([ExtensionType.PausableConfig]) → SystemProgram.createAccount → createInitializePausableConfigInstruction(pauseAuthority) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash \`tsc --noEmit\` +- Bash run existing test suite if present +- Confirm pause authority is set correctly +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work`} + + +```text +--- +description: Create a Token-2022 mint with Pausable and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with Pausable and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/pausable-mint +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Restriction: compression_only accounts required + +SPL equivalent: createInitializePausableInstruction() + createMint() +Light Token: createInitializePausableInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep `@solana/spl-token|Connection|Keypair|Pausable|TOKEN_2022` across src/ +- Glob `**/*.ts` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with pausable +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with pausable, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Note: when paused, all minting, burning, and transfers are rejected until resumed +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` +- Create T22 mint: getMintLen([ExtensionType.PausableConfig]) → SystemProgram.createAccount → createInitializePausableConfigInstruction(pauseAuthority) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash `tsc --noEmit` +- Bash run existing test suite if present +- Confirm pause authority is set correctly +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work +``` diff --git a/snippets/ai-prompts/extensions/permanent-delegate.mdx b/snippets/ai-prompts/extensions/permanent-delegate.mdx new file mode 100644 index 0000000..7758b41 --- /dev/null +++ b/snippets/ai-prompts/extensions/permanent-delegate.mdx @@ -0,0 +1,123 @@ + +{`--- +description: Create a Token-2022 mint with PermanentDelegate and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with PermanentDelegate and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/permanent-delegate +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Restriction: compression_only accounts required + +SPL equivalent: createInitializePermanentDelegateInstruction() + createMint() +Light Token: createInitializePermanentDelegateInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep \`@solana/spl-token|Connection|Keypair|PermanentDelegate|TOKEN_2022\` across src/ +- Glob \`**/*.ts\` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with permanent delegate +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with permanent delegate, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Ensure the delegate address is correct — this authority is irrevocable once set +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` +- Create T22 mint: getMintLen([ExtensionType.PermanentDelegate]) → SystemProgram.createAccount → createInitializePermanentDelegateInstruction(delegate) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash \`tsc --noEmit\` +- Bash run existing test suite if present +- Confirm delegate address is intentional (irrevocable) +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work`} + + +```text +--- +description: Create a Token-2022 mint with PermanentDelegate and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with PermanentDelegate and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/permanent-delegate +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Restriction: compression_only accounts required + +SPL equivalent: createInitializePermanentDelegateInstruction() + createMint() +Light Token: createInitializePermanentDelegateInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep `@solana/spl-token|Connection|Keypair|PermanentDelegate|TOKEN_2022` across src/ +- Glob `**/*.ts` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with permanent delegate +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with permanent delegate, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Ensure the delegate address is correct — this authority is irrevocable once set +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` +- Create T22 mint: getMintLen([ExtensionType.PermanentDelegate]) → SystemProgram.createAccount → createInitializePermanentDelegateInstruction(delegate) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash `tsc --noEmit` +- Bash run existing test suite if present +- Confirm delegate address is intentional (irrevocable) +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work +``` diff --git a/snippets/ai-prompts/extensions/token-groups-and-members.mdx b/snippets/ai-prompts/extensions/token-groups-and-members.mdx new file mode 100644 index 0000000..2f297ab --- /dev/null +++ b/snippets/ai-prompts/extensions/token-groups-and-members.mdx @@ -0,0 +1,123 @@ + +{`--- +description: Create Token-2022 group and member mints and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create Token-2022 group and member mints and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/token-groups-and-members +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token + +SPL equivalent: createInitializeGroupPointerInstruction() + createInitializeGroupInstruction() +Light Token: createInitializeGroupPointerInstruction() + createInitializeGroupInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep \`@solana/spl-token|Connection|Keypair|GroupPointer|TOKEN_2022\` across src/ +- Glob \`**/*.ts\` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 group and member mints +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 group/member mints, register existing T22 mints, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Plan covers both group mint creation (GroupPointer + TokenGroup) and member mint creation (GroupMemberPointer + TokenGroupMember) +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` +- Create group mint: getMintLen([ExtensionType.GroupPointer, ExtensionType.TokenGroup]) → SystemProgram.createAccount → createInitializeGroupPointerInstruction → createInitializeMint2Instruction → createInitializeGroupInstruction +- Create member mint: getMintLen([ExtensionType.GroupMemberPointer, ExtensionType.TokenGroupMember]) → SystemProgram.createAccount → createInitializeGroupMemberPointerInstruction → createInitializeMint2Instruction → createInitializeMemberInstruction +- Register both mints: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash \`tsc --noEmit\` +- Bash run existing test suite if present +- Confirm both group and member mints are created and registered +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work`} + + +```text +--- +description: Create Token-2022 group and member mints and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create Token-2022 group and member mints and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/token-groups-and-members +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token + +SPL equivalent: createInitializeGroupPointerInstruction() + createInitializeGroupInstruction() +Light Token: createInitializeGroupPointerInstruction() + createInitializeGroupInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep `@solana/spl-token|Connection|Keypair|GroupPointer|TOKEN_2022` across src/ +- Glob `**/*.ts` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 group and member mints +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 group/member mints, register existing T22 mints, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Plan covers both group mint creation (GroupPointer + TokenGroup) and member mint creation (GroupMemberPointer + TokenGroupMember) +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` +- Create group mint: getMintLen([ExtensionType.GroupPointer, ExtensionType.TokenGroup]) → SystemProgram.createAccount → createInitializeGroupPointerInstruction → createInitializeMint2Instruction → createInitializeGroupInstruction +- Create member mint: getMintLen([ExtensionType.GroupMemberPointer, ExtensionType.TokenGroupMember]) → SystemProgram.createAccount → createInitializeGroupMemberPointerInstruction → createInitializeMint2Instruction → createInitializeMemberInstruction +- Register both mints: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash `tsc --noEmit` +- Bash run existing test suite if present +- Confirm both group and member mints are created and registered +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work +``` diff --git a/snippets/ai-prompts/extensions/transfer-fees.mdx b/snippets/ai-prompts/extensions/transfer-fees.mdx new file mode 100644 index 0000000..409fe1f --- /dev/null +++ b/snippets/ai-prompts/extensions/transfer-fees.mdx @@ -0,0 +1,123 @@ + +{`--- +description: Create a Token-2022 mint with TransferFeeConfig and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with TransferFeeConfig and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/transfer-fees +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Constraint: fees MUST be zero (0 basis points, 0 maximum fee) + +SPL equivalent: createInitializeTransferFeeConfigInstruction() + createMint() +Light Token: createInitializeTransferFeeConfigInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep \`@solana/spl-token|Connection|Keypair|TransferFee|TOKEN_2022\` across src/ +- Glob \`**/*.ts\` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with transfer fee extension +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with transfer fees, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Ensure fees are zero (0 basis points, BigInt(0) max fee) — non-zero fees cause Light Token registration to fail +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` +- Create T22 mint: getMintLen([ExtensionType.TransferFeeConfig]) → SystemProgram.createAccount → createInitializeTransferFeeConfigInstruction (zero fees) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash \`tsc --noEmit\` +- Bash run existing test suite if present +- Confirm fees are zero in initialization code +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work`} + + +```text +--- +description: Create a Token-2022 mint with TransferFeeConfig and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with TransferFeeConfig and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/transfer-fees +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Constraint: fees MUST be zero (0 basis points, 0 maximum fee) + +SPL equivalent: createInitializeTransferFeeConfigInstruction() + createMint() +Light Token: createInitializeTransferFeeConfigInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep `@solana/spl-token|Connection|Keypair|TransferFee|TOKEN_2022` across src/ +- Glob `**/*.ts` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with transfer fee extension +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with transfer fees, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Ensure fees are zero (0 basis points, BigInt(0) max fee) — non-zero fees cause Light Token registration to fail +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` +- Create T22 mint: getMintLen([ExtensionType.TransferFeeConfig]) → SystemProgram.createAccount → createInitializeTransferFeeConfigInstruction (zero fees) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash `tsc --noEmit` +- Bash run existing test suite if present +- Confirm fees are zero in initialization code +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work +``` diff --git a/snippets/ai-prompts/extensions/transfer-hook.mdx b/snippets/ai-prompts/extensions/transfer-hook.mdx new file mode 100644 index 0000000..1d09408 --- /dev/null +++ b/snippets/ai-prompts/extensions/transfer-hook.mdx @@ -0,0 +1,123 @@ + +{`--- +description: Create a Token-2022 mint with TransferHook and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with TransferHook and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/transfer-hook +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Constraint: program_id MUST be nil (PublicKey.default) + +SPL equivalent: createInitializeTransferHookInstruction() +Light Token: createInitializeTransferHookInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep \`@solana/spl-token|Connection|Keypair|TransferHook|TOKEN_2022\` across src/ +- Glob \`**/*.ts\` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with transfer hook +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with transfer hook, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Ensure program_id is PublicKey.default (nil) — non-nil program_id causes Light Token registration to fail +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` +- Create T22 mint: getMintLen([ExtensionType.TransferHook]) → SystemProgram.createAccount → createInitializeTransferHookInstruction (PublicKey.default) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash \`tsc --noEmit\` +- Bash run existing test suite if present +- Confirm program_id is PublicKey.default in initialization code +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work`} + + +```text +--- +description: Create a Token-2022 mint with TransferHook and register with Light Token +allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression +--- + +## Create a Token-2022 mint with TransferHook and register with Light Token + +Context: +- Guide: https://zkcompression.com/light-token/extensions/transfer-hook +- Skills and resources index: https://zkcompression.com/skill.md +- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison +- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token +- Constraint: program_id MUST be nil (PublicKey.default) + +SPL equivalent: createInitializeTransferHookInstruction() +Light Token: createInitializeTransferHookInstruction() + LightTokenProgram.createSplInterface() + +### 1. Index project +- Grep `@solana/spl-token|Connection|Keypair|TransferHook|TOKEN_2022` across src/ +- Glob `**/*.ts` for project structure +- Identify: RPC setup, existing mint logic, entry point for T22 mint with transfer hook +- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel + +### 2. Read references +- WebFetch the guide above — follow the Instruction tab for the full flow +- WebFetch skill.md — check for a dedicated skill and resources matching this task +- TaskCreate one todo per phase below to track progress + +### 3. Clarify intention +- AskUserQuestion: what is the goal? (new T22 mint with transfer hook, register existing T22 mint, migrate existing SPL code) +- AskUserQuestion: does the project already use Token-2022? +- Summarize findings and wait for user confirmation before implementing + +### 4. Create plan +- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes +- Verify existing connection/signer setup is compatible with the cookbook prerequisites +- Ensure program_id is PublicKey.default (nil) — non-nil program_id causes Light Token registration to fail +- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) +- Present the plan to the user for approval before proceeding + +### 5. Implement +- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` +- Create T22 mint: getMintLen([ExtensionType.TransferHook]) → SystemProgram.createAccount → createInitializeTransferHookInstruction (PublicKey.default) → createInitializeMint2Instruction +- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) +- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified +- Write/Edit to create or modify files +- TaskUpdate to mark each step done + +### 6. Verify +- Bash `tsc --noEmit` +- Bash run existing test suite if present +- Confirm program_id is PublicKey.default in initialization code +- TaskUpdate to mark complete + +### Tools +- mcp__zkcompression__SearchLightProtocol("") for API details +- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture +- Task subagent with Grep/Read/WebFetch for parallel lookups +- TaskList to check remaining work +``` diff --git a/snippets/ai-prompts/toolkits/payments.mdx b/snippets/ai-prompts/toolkits/payments.mdx index 56478c3..49eac2d 100644 --- a/snippets/ai-prompts/toolkits/payments.mdx +++ b/snippets/ai-prompts/toolkits/payments.mdx @@ -10,9 +10,9 @@ Context: - Guide: https://zkcompression.com/light-token/payments/integration-guide - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js -- Full examples: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets +- Full examples: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments SPL → Light Token API mapping: | Operation | SPL | Light Token | @@ -80,9 +80,9 @@ Context: - Guide: https://zkcompression.com/light-token/payments/integration-guide - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js -- Full examples: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets +- Full examples: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments SPL → Light Token API mapping: | Operation | SPL | Light Token | diff --git a/snippets/ai-prompts/toolkits/wallets.mdx b/snippets/ai-prompts/toolkits/wallets.mdx index 9d2c548..bd07e64 100644 --- a/snippets/ai-prompts/toolkits/wallets.mdx +++ b/snippets/ai-prompts/toolkits/wallets.mdx @@ -10,9 +10,9 @@ Context: - Guide: https://zkcompression.com/light-token/wallets/overview - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js -- Full examples: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets +- Full examples: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments SPL → Light Token API mapping: | Operation | SPL | Light Token | @@ -81,9 +81,9 @@ Context: - Guide: https://zkcompression.com/light-token/wallets/overview - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js -- Full examples: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets +- Full examples: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments SPL → Light Token API mapping: | Operation | SPL | Light Token | diff --git a/snippets/ai-prompts/wallets/gasless-transactions.mdx b/snippets/ai-prompts/wallets/gasless-transactions.mdx index 319efc2..1df29cf 100644 --- a/snippets/ai-prompts/wallets/gasless-transactions.mdx +++ b/snippets/ai-prompts/wallets/gasless-transactions.mdx @@ -10,7 +10,7 @@ Context: - Guide: https://zkcompression.com/light-token/wallets/gasless-transactions - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js How rent sponsorship works: @@ -84,7 +84,7 @@ Context: - Guide: https://zkcompression.com/light-token/wallets/gasless-transactions - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js How rent sponsorship works: diff --git a/snippets/ai-prompts/wallets/privy.mdx b/snippets/ai-prompts/wallets/privy.mdx index 9edfebb..1e81f3b 100644 --- a/snippets/ai-prompts/wallets/privy.mdx +++ b/snippets/ai-prompts/wallets/privy.mdx @@ -10,7 +10,7 @@ Context: - Guide: https://zkcompression.com/light-token/wallets/privy - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js - Node.js example: https://github.com/Lightprotocol/examples-light-token/tree/main/privy/nodejs - React example: https://github.com/Lightprotocol/examples-light-token/tree/main/privy/react @@ -81,7 +81,7 @@ Context: - Guide: https://zkcompression.com/light-token/wallets/privy - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js - Node.js example: https://github.com/Lightprotocol/examples-light-token/tree/main/privy/nodejs - React example: https://github.com/Lightprotocol/examples-light-token/tree/main/privy/react diff --git a/snippets/ai-prompts/wallets/wallet-adapter.mdx b/snippets/ai-prompts/wallets/wallet-adapter.mdx index a4175f5..4ab7497 100644 --- a/snippets/ai-prompts/wallets/wallet-adapter.mdx +++ b/snippets/ai-prompts/wallets/wallet-adapter.mdx @@ -10,7 +10,7 @@ Context: - Guide: https://zkcompression.com/light-token/wallets/wallet-adapter - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js - React example: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter/react @@ -79,7 +79,7 @@ Context: - Guide: https://zkcompression.com/light-token/wallets/wallet-adapter - Skills and resources index: https://zkcompression.com/skill.md - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets +- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js - React example: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter/react diff --git a/snippets/code-snippets/light-token/transfer-checked/native-program/full-example.mdx b/snippets/code-snippets/light-token/transfer-checked/native-program/full-example.mdx index 646df35..97f8e5d 100644 --- a/snippets/code-snippets/light-token/transfer-checked/native-program/full-example.mdx +++ b/snippets/code-snippets/light-token/transfer-checked/native-program/full-example.mdx @@ -24,7 +24,7 @@ pub fn transfer_checked_invoke( let amount = u64::from_le_bytes(data[0..8].try_into().unwrap()); let decimals = data[8]; - // TransferChecked validates decimals. Only for Light->Light. Use TransferInterface for SPL/T22 + // TransferChecked validates decimals. Only for Light->Light. Use TransferInterface for SPL/Token 2022 TransferCheckedCpi { source: source.clone(), mint: mint.clone(), diff --git a/snippets/code-snippets/privy/unwrap/nodejs.mdx b/snippets/code-snippets/privy/unwrap/nodejs.mdx index f344b30..4d3b898 100644 --- a/snippets/code-snippets/privy/unwrap/nodejs.mdx +++ b/snippets/code-snippets/privy/unwrap/nodejs.mdx @@ -30,7 +30,7 @@ const unwrapTokens = async ( if (!mintAccountInfo) throw new Error(`Mint account ${tokenMintAddress} not found`); const tokenProgramId = mintAccountInfo.owner; - // Destination: SPL/T22 associated token account + // Destination: SPL/Token 2022 associated token account const splAta = getAssociatedTokenAddressSync(mintPubkey, fromPubkey, false, tokenProgramId); // Returns TransactionInstruction[][]. diff --git a/snippets/code-snippets/privy/unwrap/react.mdx b/snippets/code-snippets/privy/unwrap/react.mdx index 0eeafb5..d2eb4e6 100644 --- a/snippets/code-snippets/privy/unwrap/react.mdx +++ b/snippets/code-snippets/privy/unwrap/react.mdx @@ -41,12 +41,12 @@ export function useUnwrap() { const mintPubkey = new PublicKey(mint); const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); - // Auto-detect token program (SPL vs T22) from mint account owner + // Auto-detect token program (SPL vs Token 2022) from mint account owner const mintAccountInfo = await rpc.getAccountInfo(mintPubkey); if (!mintAccountInfo) throw new Error(`Mint account ${mint} not found`); const tokenProgramId = mintAccountInfo.owner; - // Destination: SPL/T22 associated token account + // Destination: SPL/Token 2022 associated token account const splAta = getAssociatedTokenAddressSync(mintPubkey, owner, false, tokenProgramId); // Returns TransactionInstruction[][]. diff --git a/snippets/code-snippets/privy/wrap/react.mdx b/snippets/code-snippets/privy/wrap/react.mdx index 8262a39..4f8a238 100644 --- a/snippets/code-snippets/privy/wrap/react.mdx +++ b/snippets/code-snippets/privy/wrap/react.mdx @@ -43,7 +43,7 @@ export function useWrap() { const mintPubkey = new PublicKey(mint); const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); - // Get SPL interface info — determines whether mint uses SPL or T22 + // Get SPL interface info — determines whether mint uses SPL or Token 2022 const splInterfaceInfos = await getSplInterfaceInfos(rpc, mintPubkey); const splInterfaceInfo = splInterfaceInfos.find( (info) => info.isInitialized, @@ -51,7 +51,7 @@ export function useWrap() { if (!splInterfaceInfo) throw new Error('No SPL interface found for this mint'); const { tokenProgram } = splInterfaceInfo; - // Derive source associated token account using the mint's token program (SPL or T22) + // Derive source associated token account using the mint's token program (SPL or Token 2022) const splAta = getAssociatedTokenAddressSync(mintPubkey, owner, false, tokenProgram); const ataAccount = await getAccount(rpc, splAta, undefined, tokenProgram); if (ataAccount.amount < BigInt(tokenAmount)) { diff --git a/snippets/code-snippets/wallet-adapter/unwrap/react.mdx b/snippets/code-snippets/wallet-adapter/unwrap/react.mdx index cdfda00..43f1a38 100644 --- a/snippets/code-snippets/wallet-adapter/unwrap/react.mdx +++ b/snippets/code-snippets/wallet-adapter/unwrap/react.mdx @@ -38,12 +38,12 @@ export function useUnwrap() { const mintPubkey = new PublicKey(mint); const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); - // Auto-detect token program (SPL vs T22) from mint account owner + // Auto-detect token program (SPL vs Token 2022) from mint account owner const mintAccountInfo = await rpc.getAccountInfo(mintPubkey); if (!mintAccountInfo) throw new Error(`Mint account ${mint} not found`); const tokenProgramId = mintAccountInfo.owner; - // Destination: SPL/T22 associated token account + // Destination: SPL/Token 2022 associated token account const splAta = getAssociatedTokenAddressSync(mintPubkey, owner, false, tokenProgramId); // Returns TransactionInstruction[][]. diff --git a/snippets/code-snippets/wallet-adapter/wrap/react.mdx b/snippets/code-snippets/wallet-adapter/wrap/react.mdx index 8eb738d..8a96b9f 100644 --- a/snippets/code-snippets/wallet-adapter/wrap/react.mdx +++ b/snippets/code-snippets/wallet-adapter/wrap/react.mdx @@ -41,7 +41,7 @@ export function useWrap() { const mintPubkey = new PublicKey(mint); const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); - // Get SPL interface info — determines whether mint uses SPL or T22 + // Get SPL interface info — determines whether mint uses SPL or Token 2022 const splInterfaceInfos = await getSplInterfaceInfos(rpc, mintPubkey); const splInterfaceInfo = splInterfaceInfos.find( (info) => info.isInitialized, @@ -49,7 +49,7 @@ export function useWrap() { if (!splInterfaceInfo) throw new Error('No SPL interface found for this mint'); const { tokenProgram } = splInterfaceInfo; - // Derive source associated token account using the mint's token program (SPL or T22) + // Derive source associated token account using the mint's token program (SPL or Token 2022) const splAta = getAssociatedTokenAddressSync(mintPubkey, owner, false, tokenProgram); const ataAccount = await getAccount(rpc, splAta, undefined, tokenProgram); if (ataAccount.amount < BigInt(tokenAmount)) { diff --git a/snippets/extensions-table.mdx b/snippets/extensions-table.mdx new file mode 100644 index 0000000..8a7b1e0 --- /dev/null +++ b/snippets/extensions-table.mdx @@ -0,0 +1,18 @@ +| Extension | Description | +|-----------|-------------| +| [MetadataPointer](/light-token/extensions/metadata-and-metadata-pointer) | Points a mint to the account that stores its metadata. | +| [TokenMetadata](/light-token/extensions/metadata-and-metadata-pointer) | Stores token name, symbol, and URI directly on the mint. | +| [TransferFeeConfig](/light-token/extensions/transfer-fees) | Withholds a percentage of each transfer as a fee. | +| [TransferHook](/light-token/extensions/transfer-hook) | Invokes a custom program on every transfer via CPI. | +| [InterestBearingConfig](/light-token/extensions/interest-bearing-tokens) | Displays a UI-adjusted balance that accrues interest over time. | +| [DefaultAccountState](/light-token/extensions/default-account-state) | Sets the initial state (e.g., frozen) for newly created token accounts. | +| [PermanentDelegate](/light-token/extensions/permanent-delegate) | Grants an authority unrestricted transfer and burn rights over all accounts for the mint. | +| [MintCloseAuthority](/light-token/extensions/close-mint) | Allows a designated authority to close a mint account. | +| [GroupPointer](/light-token/extensions/token-groups-and-members) | Points a mint to the account that stores group configuration. | +| [GroupMemberPointer](/light-token/extensions/token-groups-and-members) | Points a mint to the account that stores group member configuration. | +| [TokenGroup](/light-token/extensions/token-groups-and-members) | Stores group configuration directly on the mint (e.g., NFT collections). | +| [TokenGroupMember](/light-token/extensions/token-groups-and-members) | Stores group member configuration directly on the mint. | +| [Pausable](/light-token/extensions/pausable-mint) | Allows an authority to pause all minting, burning, and transfers. | +| [ConfidentialTransferMint](/light-token/extensions/confidential-transfer) | Configures auditor keys for confidential (encrypted) transfers. | +| [ConfidentialTransferFeeConfig](/light-token/extensions/confidential-transfer) | Encrypts withheld transfer fees under an auditor's public key. | +| [ConfidentialMintBurn](/light-token/extensions/confidential-transfer) | Allows minting and burning of tokens with encrypted amounts. | diff --git a/snippets/overview-tables/light-token-client-examples-table.mdx b/snippets/overview-tables/light-token-client-examples-table.mdx index 1c610a2..0b532f2 100644 --- a/snippets/overview-tables/light-token-client-examples-table.mdx +++ b/snippets/overview-tables/light-token-client-examples-table.mdx @@ -2,7 +2,7 @@ | | | | |---------|-------------|-------------| -| **payments-and-wallets** | All you need for wallet integrations and payment flows. Minimal API differences to SPL. | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets) \| [Docs](/light-token/payments/integration-guide) | +| **payments** | All you need for wallet integrations and payment flows. Minimal API differences to SPL. | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments) \| [Docs](/light-token/payments/integration-guide) | | **sign-with-privy** | Light-token operations signed with Privy wallets (Node.js + React) | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy) \| [Docs](/light-token/wallets/privy) | | **sign-with-wallet-adapter** | Light-token operations signed with Wallet Adapter (React) | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter) \| [Docs](/light-token/wallets/wallet-adapter) | | **gasless-transactions** | Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees. | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions) \| [Docs](/light-token/wallets/gasless-transactions) | diff --git a/snippets/overview-tables/light-token-program-examples-table.mdx b/snippets/overview-tables/light-token-program-examples-table.mdx index d96fe4d..44a07ce 100644 --- a/snippets/overview-tables/light-token-program-examples-table.mdx +++ b/snippets/overview-tables/light-token-program-examples-table.mdx @@ -37,4 +37,4 @@ For existing programs, you can replace spl_token with light_token instructions a | **revoke** | Revoke delegate via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/revoke/src/lib.rs) \| [Docs](/light-token/cookbook/approve-revoke) | | **thaw** | Thaw token account via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/thaw/src/lib.rs) \| [Docs](/light-token/cookbook/freeze-thaw) | | **transfer-checked** | Transfer with mint validation via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/transfer-checked/src/lib.rs) \| [Docs](/light-token/cookbook/transfer-checked) | -| **transfer-interface** | Transfer between light-token, T22, and SPL accounts via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/transfer-interface/src/lib.rs) \| [Docs](/light-token/cookbook/transfer-interface) | +| **transfer-interface** | Transfer between light-token, Token 2022, and SPL accounts via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/transfer-interface/src/lib.rs) \| [Docs](/light-token/cookbook/transfer-interface) | diff --git a/snippets/setup/agent-skill-payments.mdx b/snippets/setup/agent-skill-payments.mdx index 80e5711..46ce066 100644 --- a/snippets/setup/agent-skill-payments.mdx +++ b/snippets/setup/agent-skill-payments.mdx @@ -2,7 +2,7 @@ import InstallAgentSkills from "/snippets/setup/install-agent-skills.mdx"; -Use the [payments-and-wallets](https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets) agent skill to add light-token payment support to your project: +Use the [payments](https://github.com/Lightprotocol/skills/tree/main/skills/payments) agent skill to add light-token payment support to your project: diff --git a/snippets/setup/extensions-setup.mdx b/snippets/setup/extensions-setup.mdx new file mode 100644 index 0000000..a5ceef7 --- /dev/null +++ b/snippets/setup/extensions-setup.mdx @@ -0,0 +1,18 @@ + + +```bash +npm install @lightprotocol/compressed-token@beta \ + @lightprotocol/stateless.js@beta \ + @solana/spl-token +``` + +Snippets below assume `rpc`, `payer`, `mint`, `owner`, `recipient`, and `amount` are defined. +See the [full examples](https://github.com/Lightprotocol/examples-light-token/tree/main/extensions) for runnable setup. + +```typescript +import { createRpc } from "@lightprotocol/stateless.js"; + +const rpc = createRpc(RPC_ENDPOINT); +``` + + diff --git a/snippets/setup/register-spl-mint.mdx b/snippets/setup/register-spl-mint.mdx index 57ccead..0e3688a 100644 --- a/snippets/setup/register-spl-mint.mdx +++ b/snippets/setup/register-spl-mint.mdx @@ -3,7 +3,7 @@ For existing SPL mints (e.g. USDC), register the SPL interface once. This creates the omnibus PDA that holds SPL tokens when wrapped to light-token. -Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments-and-wallets/register-spl-mint.ts). +Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/register-spl-mint.ts). Check if the interface already exists: From 14f135d807dc4cfb884ac1b6e0b7f3930a3d026d Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Thu, 19 Mar 2026 23:02:11 +0000 Subject: [PATCH 08/19] lots of adds --- api-reference/solana-to-light-comparison.mdx | 40 +++++++++ docs.json | 8 +- light-token/cookbook/add-interface-pda.mdx | 29 ++---- light-token/cookbook/approve-revoke.mdx | 57 +++++++----- light-token/cookbook/burn.mdx | 16 ++-- light-token/cookbook/close-token-account.mdx | 16 ++-- light-token/cookbook/create-ata.mdx | 16 ++-- light-token/cookbook/create-mint.mdx | 16 ++-- light-token/cookbook/create-token-account.mdx | 17 ++-- light-token/cookbook/freeze-thaw.mdx | 16 ++-- light-token/cookbook/load-ata.mdx | 10 +++ light-token/cookbook/mint-to.mdx | 16 ++-- light-token/cookbook/transfer-checked.mdx | 62 ++++--------- light-token/cookbook/transfer-delegated.mdx | 52 +++++++++++ light-token/cookbook/transfer-interface.mdx | 88 +++++++++++++++---- light-token/cookbook/wrap-unwrap.mdx | 10 +++ light-token/extensions/close-mint.mdx | 49 +---------- .../extensions/confidential-transfer.mdx | 72 +-------------- .../extensions/default-account-state.mdx | 49 +---------- .../extensions/interest-bearing-tokens.mdx | 50 +---------- .../metadata-and-metadata-pointer.mdx | 54 +----------- light-token/extensions/pausable-mint.mdx | 52 ++--------- light-token/extensions/permanent-delegate.mdx | 49 +---------- .../extensions/token-groups-and-members.mdx | 69 +-------------- light-token/extensions/transfer-fees.mdx | 58 +----------- light-token/extensions/transfer-hook.mdx | 51 +---------- light-token/payments/production-readiness.mdx | 31 +------ light-token/payments/spend-permissions.mdx | 58 ++++++++++++ .../program-cookbook/transfer-checked.mdx | 6 ++ snippets/ai-prompts/toolkits/payments.mdx | 2 + .../ts-cookbook/transfer-interface.mdx | 12 ++- .../code-samples/code-compare-snippets.jsx | 16 ++-- .../approve-revoke/approve-action.mdx | 25 +++--- .../approve-revoke/revoke-action.mdx | 34 ++++--- .../spend-permissions/delegate-full-flow.mdx | 38 +++++++- .../delegate-transfer-instruction.mdx | 34 +++++++ .../spend-permissions/delegate-transfer.mdx | 27 ++++++ snippets/migration-reference/ts/approve.mdx | 9 +- snippets/migration-reference/ts/revoke.mdx | 7 +- 39 files changed, 559 insertions(+), 762 deletions(-) create mode 100644 light-token/cookbook/transfer-delegated.mdx create mode 100644 snippets/code-snippets/payments/spend-permissions/delegate-transfer-instruction.mdx create mode 100644 snippets/code-snippets/payments/spend-permissions/delegate-transfer.mdx diff --git a/api-reference/solana-to-light-comparison.mdx b/api-reference/solana-to-light-comparison.mdx index e532f64..b10d053 100644 --- a/api-reference/solana-to-light-comparison.mdx +++ b/api-reference/solana-to-light-comparison.mdx @@ -895,6 +895,46 @@ let ix = approve(
+### Delegated transfer + +Transfer tokens as an approved delegate. The delegate is the transaction authority; the owner's signature is not required. + +> [Guide](/light-token/payments/spend-permissions) + + + + +```typescript title="Light" +import { transferDelegatedInterface } from "@lightprotocol/compressed-token/unified"; + +const tx = await transferDelegatedInterface( + rpc, + payer, + sourceAta, + mint, + recipient, + delegate, + owner.publicKey, + amount +); +``` +```typescript title="SPL" +import { transfer } from "@solana/spl-token"; + +// delegate signs instead of owner +const tx = await transfer( + connection, + payer, + sourceAta, + destinationAta, + delegate, + amount +); +``` + + + + ### Revoke delegate Remove all delegate permissions. diff --git a/docs.json b/docs.json index c9392bf..141a652 100644 --- a/docs.json +++ b/docs.json @@ -51,7 +51,13 @@ "light-token/cookbook/mint-to", "light-token/cookbook/transfer-interface", "light-token/cookbook/transfer-checked", - "light-token/cookbook/approve-revoke", + { + "group": "Delegates", + "pages": [ + "light-token/cookbook/approve-revoke", + "light-token/cookbook/transfer-delegated" + ] + }, "light-token/cookbook/freeze-thaw", "light-token/cookbook/wrap-unwrap", "light-token/cookbook/load-ata", diff --git a/light-token/cookbook/add-interface-pda.mdx b/light-token/cookbook/add-interface-pda.mdx index b0682df..6a30f72 100644 --- a/light-token/cookbook/add-interface-pda.mdx +++ b/light-token/cookbook/add-interface-pda.mdx @@ -17,30 +17,11 @@ import SupportFooter from "/snippets/support-footer.mdx"; -# Related guides +## Related Guides - - - - - + + + + diff --git a/light-token/cookbook/approve-revoke.mdx b/light-token/cookbook/approve-revoke.mdx index 8141d64..ae79771 100644 --- a/light-token/cookbook/approve-revoke.mdx +++ b/light-token/cookbook/approve-revoke.mdx @@ -1,7 +1,7 @@ --- title: Approve and Revoke Delegates sidebarTitle: Approve / Revoke -description: Rust client guide to approve and revoke delegates for Light Token accounts. Includes step-by-step implementation and full code examples. +description: Guide to approve and revoke delegates for Light Token accounts. Includes step-by-step implementation and full code examples. keywords: ["approve delegate solana", "revoke delegate solana", "token delegation"] --- @@ -32,6 +32,7 @@ import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import ApproveRevokeAiPrompt from "/snippets/ai-prompts/ts-cookbook/approve-revoke.mdx"; import RustApproveRevokeAiPrompt from "/snippets/ai-prompts/rust-cookbook/approve-revoke.mdx"; import ProgramApproveRevokeAiPrompt from "/snippets/ai-prompts/program-cookbook/approve-revoke.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; 1. Approve grants a delegate permission to transfer up to a specified amount of tokens from your account. * Each token account can have only one delegate at a time. @@ -48,7 +49,7 @@ import ProgramApproveRevokeAiPrompt from "/snippets/ai-prompts/program-cookbook/ -`approve` grants a delegate permission to transfer up to a specified amount of tokens. +`approveInterface` grants a delegate permission to transfer up to a specified amount of tokens. -`revoke` removes all delegate permissions from a Light Token account. +`revokeInterface` removes all delegate permissions from a Light Token account. - - Find the source code: - [delegate-approve.ts](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-approve.ts) - | - [delegate-revoke.ts](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-revoke.ts) - - -### Approve a delegate +### Prerequisites - - -### Revoke a delegate +### Approve or revoke delegates + + + Find the source code: + [delegate-approve.ts](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-approve.ts) + | + [delegate-revoke.ts](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-revoke.ts) + + + + + + + + + + + + + + + + @@ -319,12 +333,11 @@ revoke_cpi.invoke_signed(&[signer_seeds])?; -# Next Steps +## Related Guides - + + + + + + diff --git a/light-token/cookbook/burn.mdx b/light-token/cookbook/burn.mdx index 23e1649..39a5b7b 100644 --- a/light-token/cookbook/burn.mdx +++ b/light-token/cookbook/burn.mdx @@ -19,6 +19,7 @@ import AnchorProgramCode from "/snippets/code-snippets/light-token/burn/anchor-p import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import RustBurnAiPrompt from "/snippets/ai-prompts/rust-cookbook/burn.mdx"; import ProgramBurnAiPrompt from "/snippets/ai-prompts/program-cookbook/burn.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; 1. Burn permanently destroys tokens by reducing the balance in a token account. @@ -145,12 +146,11 @@ BurnCpi { -# Next Steps +## Related Guides - + + + + + + diff --git a/light-token/cookbook/close-token-account.mdx b/light-token/cookbook/close-token-account.mdx index 8e8628d..ab7f672 100644 --- a/light-token/cookbook/close-token-account.mdx +++ b/light-token/cookbook/close-token-account.mdx @@ -20,6 +20,7 @@ import AnchorProgramCode from "/snippets/code-snippets/light-token/close-token-a import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import RustCloseTokenAccountAiPrompt from "/snippets/ai-prompts/rust-cookbook/close-token-account.mdx"; import ProgramCloseTokenAccountAiPrompt from "/snippets/ai-prompts/program-cookbook/close-token-account.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; 1. Closing a Light Token account transfers remaining lamports to a destination account and the rent sponsor can reclaim sponsored rent. 2. Light token accounts can be closed by the owner. @@ -152,14 +153,11 @@ CloseAccountCpi { -# Next Steps +## Related Guides -{" "} + + + + - + diff --git a/light-token/cookbook/create-ata.mdx b/light-token/cookbook/create-ata.mdx index 125b728..831ff42 100644 --- a/light-token/cookbook/create-ata.mdx +++ b/light-token/cookbook/create-ata.mdx @@ -32,6 +32,7 @@ import CreateAtaAiPrompt from "/snippets/ai-prompts/ts-cookbook/create-ata.mdx"; import RustCreateAtaAiPrompt from "/snippets/ai-prompts/rust-cookbook/create-ata.mdx"; import ProgramCreateAtaCpiAiPrompt from "/snippets/ai-prompts/program-cookbook/create-ata-cpi.mdx"; import ProgramCreateAtaMacrosAiPrompt from "/snippets/ai-prompts/program-cookbook/create-ata-macros.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; 1. Associated Light Token accounts can hold token balances of light, SPL, or Token 2022 mints. 2. Light-ATAs are on-chain accounts like SPL ATA's, but the light token program sponsors the rent-exemption cost for you. @@ -337,14 +338,11 @@ pub ata: UncheckedAccount<'info>, -# Next Steps +## Related Guides -{" "} + + + + - + diff --git a/light-token/cookbook/create-mint.mdx b/light-token/cookbook/create-mint.mdx index d223ee1..b79f720 100644 --- a/light-token/cookbook/create-mint.mdx +++ b/light-token/cookbook/create-mint.mdx @@ -44,6 +44,7 @@ import CreateMintAiPrompt from "/snippets/ai-prompts/ts-cookbook/create-mint.mdx import RustCreateMintAiPrompt from "/snippets/ai-prompts/rust-cookbook/create-mint.mdx"; import ProgramCreateMintCpiAiPrompt from "/snippets/ai-prompts/program-cookbook/create-mint-cpi.mdx"; import ProgramCreateMintMacrosAiPrompt from "/snippets/ai-prompts/program-cookbook/create-mint-macros.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; 1. Mint accounts uniquely represent a token on Solana and store its global metadata. 2. Light mints are on-chain accounts like SPL mints, but the light token program sponsors the rent-exemption cost for you. @@ -556,12 +557,11 @@ pub mint: UncheckedAccount<'info>, -# Next Steps +## Related Guides - + + + + + + diff --git a/light-token/cookbook/create-token-account.mdx b/light-token/cookbook/create-token-account.mdx index fdf7c8f..0deab88 100644 --- a/light-token/cookbook/create-token-account.mdx +++ b/light-token/cookbook/create-token-account.mdx @@ -26,6 +26,7 @@ import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import RustCreateTokenAccountAiPrompt from "/snippets/ai-prompts/rust-cookbook/create-token-account.mdx"; import ProgramCreateTokenAccountCpiAiPrompt from "/snippets/ai-prompts/program-cookbook/create-token-account-cpi.mdx"; import ProgramCreateTokenAccountMacrosAiPrompt from "/snippets/ai-prompts/program-cookbook/create-token-account-macros.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; 1. Light token accounts are Solana accounts that hold token balances of light, SPL, or Token 2022 mints. 2. Light token accounts are on-chain accounts like SPL ATA's, but the light token program sponsors the rent-exemption cost for you. @@ -276,11 +277,11 @@ pub vault: UncheckedAccount<'info>, -# Next Steps - +## Related Guides + + + + + + + diff --git a/light-token/cookbook/freeze-thaw.mdx b/light-token/cookbook/freeze-thaw.mdx index 9095fb9..d5121e6 100644 --- a/light-token/cookbook/freeze-thaw.mdx +++ b/light-token/cookbook/freeze-thaw.mdx @@ -22,6 +22,7 @@ import ThawAnchorProgramCode from "/snippets/code-snippets/light-token/thaw/anch import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import RustFreezeThawAiPrompt from "/snippets/ai-prompts/rust-cookbook/freeze-thaw.mdx"; import ProgramFreezeThawAiPrompt from "/snippets/ai-prompts/program-cookbook/freeze-thaw.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; 1. Freeze prevents all transfers or token burns from a specific Light Token account. 2. Once frozen, the account cannot send tokens, receive tokens, or be closed until it is thawed. @@ -235,12 +236,11 @@ ThawCpi { -# Next Steps +## Related Guides - + + + + + + diff --git a/light-token/cookbook/load-ata.mdx b/light-token/cookbook/load-ata.mdx index 8f40f1c..2104091 100644 --- a/light-token/cookbook/load-ata.mdx +++ b/light-token/cookbook/load-ata.mdx @@ -9,6 +9,7 @@ import FullSetup from "/snippets/setup/full-setup.mdx"; import ActionCode from "/snippets/code-snippets/light-token/load-ata/action.mdx"; import InstructionCode from "/snippets/code-snippets/light-token/load-ata/instruction.mdx"; import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; 1. `loadAta` unifies tokens from multiple sources to a single ATA: * Compressed tokens (cold Light Tokens) -> Decompresses -> light ATA @@ -42,3 +43,12 @@ Find the source code [here](https://github.com/Lightprotocol/light-protocol/blob + +## Related Guides + + + + + + + diff --git a/light-token/cookbook/mint-to.mdx b/light-token/cookbook/mint-to.mdx index 0aa524a..c2ba876 100644 --- a/light-token/cookbook/mint-to.mdx +++ b/light-token/cookbook/mint-to.mdx @@ -28,6 +28,7 @@ import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import MintToAiPrompt from "/snippets/ai-prompts/ts-cookbook/mint-to.mdx"; import RustMintToAiPrompt from "/snippets/ai-prompts/rust-cookbook/mint-to.mdx"; import ProgramMintToAiPrompt from "/snippets/ai-prompts/program-cookbook/mint-to.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; 1. Mint To creates new tokens of a mint and deposits them to a specified token account. @@ -212,12 +213,11 @@ MintToCpi { -# Next Steps +## Related Guides - + + + + + + diff --git a/light-token/cookbook/transfer-checked.mdx b/light-token/cookbook/transfer-checked.mdx index 4d7bac6..254ed4b 100644 --- a/light-token/cookbook/transfer-checked.mdx +++ b/light-token/cookbook/transfer-checked.mdx @@ -1,62 +1,33 @@ --- title: Transfer Checked sidebarTitle: Transfer Checked -description: Rust client guide to transfer Light Tokens with decimal validation. Includes step-by-step implementation and full code examples. +description: Program CPI guide for Light Token transfer with decimal validation. Includes step-by-step implementation and full code examples. keywords: ["transfer tokens solana", "checked transfer", "decimal validation"] --- ---- - -import TokenClientPrerequisites from "/snippets/light-token-guides/light-token-client-prerequisites.mdx"; -import RustActionCode from "/snippets/code-snippets/light-token/transfer-checked/rust-client/action.mdx"; -import RustInstructionCode from "/snippets/code-snippets/light-token/transfer-checked/rust-client/instruction.mdx"; import AnchorProgramCode from "/snippets/code-snippets/light-token/transfer-checked/anchor-program/full-example.mdx"; import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; -import RustTransferCheckedAiPrompt from "/snippets/ai-prompts/rust-cookbook/transfer-checked.mdx"; import ProgramTransferCheckedAiPrompt from "/snippets/ai-prompts/program-cookbook/transfer-checked.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; 1. TransferChecked validates that the decimals parameter matches the mint's decimals. -2. Use for Light→Light transfers when you need decimal verification. -3. For transfers involving SPL or Token 2022 accounts, use [Transfer Interface](/light-token/cookbook/transfer-interface) instead. +2. Use `TransferCheckedCpi` for Light-to-Light transfers in on-chain programs when you need decimal verification without interface routing. +3. For transfers involving SPL or Token 2022 accounts, use [Transfer Interface](/light-token/cookbook/transfer-interface) instead. It uses `transferChecked` under the hood. - - - - - - -### Prerequisites - + - +`transferChecked` is called automatically under the hood by [`transferInterface`](/light-token/cookbook/transfer-interface) and `createTransferInterfaceInstructions`. You do not need to call it directly. - -### Transfer with Decimal Check + - - Find the source code [here](https://github.com/Lightprotocol/light-protocol/blob/main/sdk-libs/token-sdk/src/instruction/transfer_checked.rs). - + - - - - - - - - +`TransferChecked` is called automatically under the hood by [`TransferInterface`](/light-token/cookbook/transfer-interface). You do not need to call it directly. - - - - - - - @@ -136,14 +107,11 @@ TransferCheckedCpi { -# Next Steps +## Related Guides -{" "} + + + + - + diff --git a/light-token/cookbook/transfer-delegated.mdx b/light-token/cookbook/transfer-delegated.mdx new file mode 100644 index 0000000..1a8c956 --- /dev/null +++ b/light-token/cookbook/transfer-delegated.mdx @@ -0,0 +1,52 @@ +--- +title: Delegated Transfer +sidebarTitle: Delegated Transfer +description: Transfer tokens as an approved delegate. The delegate signs instead of the owner, spending within the approved allowance. +keywords: ["delegated transfer solana", "delegate transfer light token", "token delegation transfer"] +--- + +import FullSetup from "/snippets/setup/full-setup.mdx"; +import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; +import DelegateTransferAction from "/snippets/code-snippets/payments/spend-permissions/delegate-transfer.mdx"; +import DelegateTransferInstruction from "/snippets/code-snippets/payments/spend-permissions/delegate-transfer-instruction.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; + +`transferDelegatedInterface` transfers tokens from an associated token account as an approved delegate. The delegate is the transaction authority. Only the delegate and fee payer sign; the owner's signature is not required. + +- The recipient is a wallet address (associated token account derived and created internally) +- The amount must be within the approved allowance +- Each transfer reduces the remaining allowance + + + + + + + + +### Delegated Transfer + + + + + + + + + + + + + + + + + +## Related Guides + + + + + + + diff --git a/light-token/cookbook/transfer-interface.mdx b/light-token/cookbook/transfer-interface.mdx index 2e2a424..a78879f 100644 --- a/light-token/cookbook/transfer-interface.mdx +++ b/light-token/cookbook/transfer-interface.mdx @@ -1,6 +1,6 @@ --- title: Transfer Interface -description: Program and client guide for transfers between Light Token and SPL token accounts. The interface detects account types and invokes the right programs. +description: Transfer tokens between Light Token, SPL and Token 2022 accounts. The interface checks decimals under the hood and detects account types to invoke the right programs. keywords: ["transfer tokens on solana", "token transfer on solana", "interface methods on solana", "spl transfer for developers"] --- @@ -26,6 +26,7 @@ import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import TransferInterfaceAiPrompt from "/snippets/ai-prompts/ts-cookbook/transfer-interface.mdx"; import RustTransferInterfaceAiPrompt from "/snippets/ai-prompts/rust-cookbook/transfer-interface.mdx"; import ProgramTransferInterfaceAiPrompt from "/snippets/ai-prompts/program-cookbook/transfer-interface.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; @@ -39,20 +40,20 @@ import ProgramTransferInterfaceAiPrompt from "/snippets/ai-prompts/program-cookb - + - + @@ -66,7 +67,7 @@ import ProgramTransferInterfaceAiPrompt from "/snippets/ai-prompts/program-cookb -The `transferInterface` function transfers tokens between token accounts (SPL, Token 2022, or Light) in a single call. +The `transferInterface` function transfers tokens between token accounts (SPL, Token 2022, or Light) in a single call and checks decimals. Compare to SPL: @@ -108,11 +109,69 @@ Compare to SPL: +### Advanced: Explicit Destination Account + +For PDA destinations or program-owned accounts where you need to specify the exact destination token account, use `transferToAccountInterface`. This is an edge case; most transfers should use `transferInterface` with a wallet address. + + + + +```typescript +import { + transferToAccountInterface, + getAssociatedTokenAddressInterface, +} from "@lightprotocol/compressed-token"; + +// The destination must be an existing token account (not a wallet address). +await transferToAccountInterface( + rpc, + payer, + sourceAta, + mint, + destinationTokenAccount, + owner, + amount, +); +``` + + + + +```typescript +import { + createTransferToAccountInterfaceInstructions, + getMintInterface, + sliceLast, +} from "@lightprotocol/compressed-token"; + +const decimals = (await getMintInterface(rpc, mint)).mint.decimals; + +// Returns TransactionInstruction[][]. The destination must be an existing token account. +const batches = await createTransferToAccountInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + destinationTokenAccount, + decimals, +); + +const { rest: loads, last: transfer } = sliceLast(batches); +``` + + + + + +Both `transferInterface` and `transferToAccountInterface` reject off-curve owners. For PDA-owned source accounts (smart wallets), use [`createLightTokenTransferInstruction`](/light-token/wallets/smart-wallets). + + -Use the unified `TransferInterface` to transfer tokens between token accounts (SPL, Token 2022, or Light) in a single call. +Use the unified `TransferInterface` to transfer tokens between token accounts (SPL, Token 2022, or Light) in a single call and checks decimals. -# Next Steps +## Related Guides -{" "} + + + + - + diff --git a/light-token/cookbook/wrap-unwrap.mdx b/light-token/cookbook/wrap-unwrap.mdx index 0e60179..def603e 100644 --- a/light-token/cookbook/wrap-unwrap.mdx +++ b/light-token/cookbook/wrap-unwrap.mdx @@ -18,6 +18,7 @@ import TokenClientPrerequisites from "/snippets/light-token-guides/light-token-c import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import WrapUnwrapAiPrompt from "/snippets/ai-prompts/ts-cookbook/wrap-unwrap.mdx"; import RustWrapUnwrapAiPrompt from "/snippets/ai-prompts/rust-cookbook/wrap-unwrap.mdx"; +import SupportFooter from "/snippets/support-footer.mdx"; - **Wrap**: Move tokens from SPL/Token 2022 account → Light Token ATA (hot balance) - **Unwrap**: Move tokens from Light Token ATA (hot balance) → SPL/Token 2022 account @@ -152,3 +153,12 @@ import RustWrapUnwrapAiPrompt from "/snippets/ai-prompts/rust-cookbook/wrap-unwr + +## Related Guides + + + + + + + diff --git a/light-token/extensions/close-mint.mdx b/light-token/extensions/close-mint.mdx index 58b0752..b4793ca 100644 --- a/light-token/extensions/close-mint.mdx +++ b/light-token/extensions/close-mint.mdx @@ -16,7 +16,7 @@ A designated authority can close a mint account and reclaim its rent-exempt lamp MintCloseAuthority mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) for transfers — compressed transfer instructions are not supported. -## Key Concepts +## Key Parameters MintCloseAuthority is configured with one parameter: @@ -26,13 +26,6 @@ MintCloseAuthority is configured with one parameter: Standard SPL mints cannot be closed once created, leaving rent-exempt lamports locked permanently. MintCloseAuthority adds a close authority that can reclaim those lamports after the total supply reaches zero. -## How It Works - -1. A mint authority creates a Token-2022 mint with the MintCloseAuthority extension -2. The close authority is set at initialization -3. All tokens must be burned, reducing the total supply to zero -4. The close authority submits a close instruction to reclaim the mint account's rent - ## Use MintCloseAuthority With Light Token @@ -42,9 +35,6 @@ Standard SPL mints cannot be closed once created, leaving rent-exempt lamports l - - - ### Create a Token-2022 Mint With Close Authority @@ -153,12 +143,9 @@ const { mint, transactionSignature } = await createMintInterface( - - - -### Register an Existing Mint +### Create Interface PDA for Existing Mint -If you already have a Token-2022 mint with MintCloseAuthority, register it with Light Token. +If you already have a Token-2022 mint with MintCloseAuthority, create an interface PDA with Light Token. ```typescript import { LightTokenProgram } from "@lightprotocol/compressed-token"; @@ -171,36 +158,6 @@ const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ }); ``` - - - -### Transfer Tokens - -Transfers work identically to any other Light Token mint. The close authority can reclaim rent only after all tokens are burned. - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, - payer.publicKey, - mint, - amount, - owner.publicKey, - recipient -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); -} -``` - - - - - diff --git a/light-token/extensions/confidential-transfer.mdx b/light-token/extensions/confidential-transfer.mdx index 321e215..2ba06c8 100644 --- a/light-token/extensions/confidential-transfer.mdx +++ b/light-token/extensions/confidential-transfer.mdx @@ -16,7 +16,7 @@ Encrypt token transfer amounts using ElGamal encryption so they are not visible Light Token supports confidential transfer extensions in their **initialized-but-disabled state** only. You can create Token-2022 mints with these extensions configured and register them with Light Token, but the confidential transfer features (encrypted amounts, confidential fees, confidential minting/burning) cannot be actively used through Light Token. -## Key Concepts +## Key Parameters The confidential transfer family includes three extensions: @@ -26,14 +26,6 @@ The confidential transfer family includes three extensions: | `ConfidentialTransferFeeConfig` | `authority`, `withdrawWithheldAuthorityElGamalPubkey`, `harvestToMintEnabled`, `withheldAmount` | Fees **must be zero**. The extension can be initialized for compatibility, but confidential fee collection is not supported. | | `ConfidentialMintBurn` | `confidentialSupply`, `decryptableSupply`, `supplyElGamalPubkey` | Initialized but **not enabled**. The extension can exist on the mint, but encrypted minting and burning cannot be performed through Light Token. | -## How It Works - -1. A mint authority creates a Token-2022 mint with one or more confidential transfer extensions -2. The extensions are initialized with their configuration parameters (authority, auditor key, auto-approve settings) -3. The extensions remain in an initialized-but-disabled state — no encrypted transfers, fees, or minting/burning occur -4. The mint is registered with Light Token, which validates the extensions are in their disabled state -5. Transfers through Light Token use standard (non-encrypted) amounts - ## Use Confidential Transfer With Light Token @@ -43,14 +35,8 @@ The confidential transfer family includes three extensions: - - - ### Create a Token-2022 Mint With ConfidentialTransferMint - - - ```typescript import { Keypair, @@ -174,36 +160,9 @@ const signature = await sendAndConfirmTransaction(rpc, tx, [ ]); ``` - - - -```typescript -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMintInterface } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const { mint, transactionSignature } = await createMintInterface( - rpc, payer, payer, null, 9, mintKeypair, undefined, TOKEN_2022_PROGRAM_ID -); -``` - - -`createMintInterface` creates a basic Token-2022 mint with an interface PDA. To include the ConfidentialTransferMint extension, use the instruction approach shown in the other tab. - - - - - - +### Create Interface PDA for Existing Mint - -### Register an Existing Mint - -If you already have a Token-2022 mint with confidential transfer extensions in their disabled state, register it with Light Token. +If you already have a Token-2022 mint with ConfidentialTransferMint, create an interface PDA with Light Token. ```typescript import { LightTokenProgram } from "@lightprotocol/compressed-token"; @@ -216,31 +175,6 @@ const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ }); ``` - - - -### Transfer Tokens - -Transfers work identically to any other Light Token mint. The SDK handles loading cold balances automatically. Because confidential transfer is initialized but not enabled, all amounts remain unencrypted. - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, payer.publicKey, mint, amount, owner.publicKey, recipient -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); -} -``` - - - - - diff --git a/light-token/extensions/default-account-state.mdx b/light-token/extensions/default-account-state.mdx index 65ed1f8..507225c 100644 --- a/light-token/extensions/default-account-state.mdx +++ b/light-token/extensions/default-account-state.mdx @@ -16,7 +16,7 @@ Every new token account created under a mint starts in a specified state, such a DefaultAccountState mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) for transfers — compressed transfer instructions are not supported. -## Key Concepts +## Key Parameters DefaultAccountState is configured with two parameters: @@ -27,13 +27,6 @@ DefaultAccountState is configured with two parameters: When a new token account is created for this mint, the token program automatically sets its state to the configured default. If the default is `Frozen`, the account cannot send or receive tokens until the freeze authority thaws it. -## How It Works - -1. A mint authority creates a Token-2022 mint with the DefaultAccountState extension -2. The default state is set at initialization (typically `Frozen`) -3. Every new token account for that mint starts in the configured state -4. The freeze authority thaws individual accounts after verifying the holder - ## Use DefaultAccountState With Light Token @@ -43,9 +36,6 @@ When a new token account is created for this mint, the token program automatical - - - ### Create a Token-2022 Mint With Default Account State @@ -155,12 +145,9 @@ const { mint, transactionSignature } = await createMintInterface( - - - -### Register an Existing Mint +### Create Interface PDA for Existing Mint -If you already have a Token-2022 mint with DefaultAccountState, register it with Light Token. +If you already have a Token-2022 mint with DefaultAccountState, create an interface PDA with Light Token. ```typescript import { LightTokenProgram } from "@lightprotocol/compressed-token"; @@ -173,36 +160,6 @@ const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ }); ``` - - - -### Transfer Tokens - -Transfers work identically to any other Light Token mint. Accounts must be thawed by the freeze authority before they can send or receive tokens. - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, - payer.publicKey, - mint, - amount, - owner.publicKey, - recipient -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); -} -``` - - - - - diff --git a/light-token/extensions/interest-bearing-tokens.mdx b/light-token/extensions/interest-bearing-tokens.mdx index 3612fc4..d6b586b 100644 --- a/light-token/extensions/interest-bearing-tokens.mdx +++ b/light-token/extensions/interest-bearing-tokens.mdx @@ -10,7 +10,7 @@ import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import InterestBearingTokensAiPrompt from "/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx"; -## Key Concepts +## Key Parameters A configurable interest rate on the mint lets clients display a UI-adjusted balance that grows over time, while the on-chain token balance remains unchanged. @@ -24,14 +24,6 @@ InterestBearingConfig is configured with these parameters: | `lastUpdateTimestamp` | Network timestamp of the most recent rate change, used as the reference for interest calculations. | | `preUpdateAverageRate` | Previous rate value preserved when the rate authority updates `currentRate`. | -## How It Works - -1. A mint authority creates a Token-2022 mint with the InterestBearingConfig extension -2. The rate authority and initial interest rate are set at initialization -3. The token program records the network timestamp as the initialization reference -4. On every balance query, clients compute accrued interest from the stored rate and elapsed time -5. The rate authority can update the rate at any time; the previous rate is preserved in `preUpdateAverageRate` - This extension is fully supported by Light Token without restrictions. ## Use InterestBearingConfig With Light Token @@ -43,9 +35,6 @@ This extension is fully supported by Light Token without restrictions. - - - ### Create a Token-2022 Mint With Interest Bearing Config @@ -157,12 +146,9 @@ const { mint, transactionSignature } = await createMintInterface( - +### Create Interface PDA for Existing Mint - -### Register an Existing Mint - -If you already have a Token-2022 mint with InterestBearingConfig, register it with Light Token. +If you already have a Token-2022 mint with InterestBearingConfig, create an interface PDA with Light Token. ```typescript import { LightTokenProgram } from "@lightprotocol/compressed-token"; @@ -175,36 +161,6 @@ const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ }); ``` - - - -### Transfer Tokens - -Transfers work identically to any other Light Token mint. The interest bearing config does not affect transfer behavior; it only changes how clients display the balance. - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, - payer.publicKey, - mint, - amount, - owner.publicKey, - recipient -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); -} -``` - - - - - diff --git a/light-token/extensions/metadata-and-metadata-pointer.mdx b/light-token/extensions/metadata-and-metadata-pointer.mdx index fc2d6c0..4df245e 100644 --- a/light-token/extensions/metadata-and-metadata-pointer.mdx +++ b/light-token/extensions/metadata-and-metadata-pointer.mdx @@ -12,7 +12,7 @@ import MetadataAndMetadataPointerAiPrompt from "/snippets/ai-prompts/extensions/ MetadataPointer tells clients where to find a mint's metadata. TokenMetadata removes the need for a separate metadata account. -## Key Concepts +## Key Parameters MetadataPointer and TokenMetadata are configured together with these parameters: @@ -28,14 +28,6 @@ MetadataPointer and TokenMetadata are configured together with these parameters: When the MetadataPointer points to the mint itself, TokenMetadata stores name, symbol, URI, and additional fields directly in the mint account data. This produces a self-describing token in a single account. -## How It Works - -1. A mint authority creates a Token-2022 mint with both the MetadataPointer and TokenMetadata extensions -2. MetadataPointer is initialized with the mint address as the metadata location -3. The mint is initialized with decimals and authorities -4. TokenMetadata is initialized with name, symbol, and URI on the mint account -5. Clients read the MetadataPointer, find the mint address, and deserialize the TokenMetadata directly from it - Both extensions work without restrictions in Light Token. ## Use MetadataPointer and TokenMetadata With Light Token @@ -47,9 +39,6 @@ Both extensions work without restrictions in Light Token. - - - ### Create a Token-2022 Mint With Metadata @@ -69,8 +58,6 @@ import { getMintLen, createInitializeMint2Instruction, ExtensionType, -} from "@solana/spl-token"; -import { createInitializeMetadataPointerInstruction, } from "@solana/spl-token"; import { @@ -183,18 +170,15 @@ const { mint, transactionSignature } = await createMintInterface( ``` -`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include MetadataPointer and TokenMetadata extensions, use the instruction approach shown in the other tab. +`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the MetadataPointer and TokenMetadata extensions, use the instruction approach shown in the other tab. - +### Create Interface PDA for Existing Mint - -### Register an Existing Mint - -If you already have a Token-2022 mint with metadata, register it with Light Token. +If you already have a Token-2022 mint with MetadataPointer and TokenMetadata, create an interface PDA with Light Token. ```typescript import { LightTokenProgram } from "@lightprotocol/compressed-token"; @@ -207,36 +191,6 @@ const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ }); ``` - - - -### Transfer Tokens - -Transfers work identically to any other Light Token mint. The metadata extensions do not affect transfer behavior. - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, - payer.publicKey, - mint, - amount, - owner.publicKey, - recipient -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); -} -``` - - - - - diff --git a/light-token/extensions/pausable-mint.mdx b/light-token/extensions/pausable-mint.mdx index 137ad9e..02f9fb8 100644 --- a/light-token/extensions/pausable-mint.mdx +++ b/light-token/extensions/pausable-mint.mdx @@ -13,10 +13,11 @@ import PausableMintAiPrompt from "/snippets/ai-prompts/extensions/pausable-mint. When paused, all minting, burning, and transfers are blocked until the authority resumes the mint. -Pausable mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) for transfers — compressed transfer instructions are not supported. +Pausable mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) +for transfers. -## Key Concepts +## Key Parameters Pausable is configured with two parameters: @@ -27,13 +28,6 @@ Pausable is configured with two parameters: When paused, the Token-2022 program rejects all transfers, mints, and burns for the token. The pause authority can resume operations at any time. -## How It Works - -1. A mint authority creates a Token-2022 mint with the Pausable extension -2. The pause authority is set at initialization, with the mint starting in an unpaused state -3. The pause authority can call `pause` to halt all minting, burning, and transfers -4. The pause authority can call `resume` to re-enable operations - ## Use Pausable With Light Token @@ -43,9 +37,6 @@ When paused, the Token-2022 program rejects all transfers, mints, and burns for - - - ### Create a Token-2022 Mint With Pausable @@ -154,12 +145,9 @@ const { mint, transactionSignature } = await createMintInterface( - - - -### Register an Existing Mint +### Create Interface PDA for Existing Mint -If you already have a Token-2022 mint with Pausable, register it with Light Token. +If you already have a Token-2022 mint with Pausable, create an interface PDA with Light Token. ```typescript import { LightTokenProgram } from "@lightprotocol/compressed-token"; @@ -172,36 +160,6 @@ const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ }); ``` - - - -### Transfer Tokens - -Transfers work identically to any other Light Token mint, as long as the mint is not currently paused. - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, - payer.publicKey, - mint, - amount, - owner.publicKey, - recipient -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); -} -``` - - - - - diff --git a/light-token/extensions/permanent-delegate.mdx b/light-token/extensions/permanent-delegate.mdx index 56fa4e0..7745ee1 100644 --- a/light-token/extensions/permanent-delegate.mdx +++ b/light-token/extensions/permanent-delegate.mdx @@ -16,7 +16,7 @@ A designated authority gains irrevocable transfer and burn rights over every tok PermanentDelegate mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) for transfers — compressed transfer instructions are not supported. -## Key Concepts +## Key Parameters PermanentDelegate is configured with one parameter: @@ -26,13 +26,6 @@ PermanentDelegate is configured with one parameter: Unlike standard delegates set per token account, the permanent delegate operates at the mint level. Token account owners cannot revoke this authority. Only the current permanent delegate can reassign the role to a new account. -## How It Works - -1. A mint authority creates a Token-2022 mint with the PermanentDelegate extension -2. The delegate address is set at initialization and cannot be removed -3. The permanent delegate can transfer or burn tokens from any token account for this mint without owner approval -4. The delegate authority persists for the lifetime of the mint - ## Use PermanentDelegate With Light Token @@ -42,9 +35,6 @@ Unlike standard delegates set per token account, the permanent delegate operates - - - ### Create a Token-2022 Mint With Permanent Delegate @@ -153,12 +143,9 @@ const { mint, transactionSignature } = await createMintInterface( - - - -### Register an Existing Mint +### Create Interface PDA for Existing Mint -If you already have a Token-2022 mint with PermanentDelegate, register it with Light Token. +If you already have a Token-2022 mint with PermanentDelegate, create an interface PDA with Light Token. ```typescript import { LightTokenProgram } from "@lightprotocol/compressed-token"; @@ -171,36 +158,6 @@ const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ }); ``` - - - -### Transfer Tokens - -Transfers work identically to any other Light Token mint. The permanent delegate retains authority to transfer or burn tokens from any account. - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, - payer.publicKey, - mint, - amount, - owner.publicKey, - recipient -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); -} -``` - - - - - diff --git a/light-token/extensions/token-groups-and-members.mdx b/light-token/extensions/token-groups-and-members.mdx index a4757d5..4962572 100644 --- a/light-token/extensions/token-groups-and-members.mdx +++ b/light-token/extensions/token-groups-and-members.mdx @@ -12,7 +12,7 @@ import TokenGroupsAndMembersAiPrompt from "/snippets/ai-prompts/extensions/token Organize tokens into hierarchical groups such as NFT collections by linking a group mint to one or more member mints through on-chain pointer and data extensions. -## Key Concepts +## Key Parameters Token groups use four related extensions that work in pairs: @@ -23,14 +23,6 @@ Token groups use four related extensions that work in pairs: | `GroupMemberPointer` | `authority`, `memberAddress` | Designates a mint as a member mint by pointing to an account that stores membership data. Typically points to the mint itself. | | `TokenGroupMember` | `mint`, `group`, `memberNumber` | Stores the membership data (parent group address, sequential member number) directly on the mint account. | -## How It Works - -1. A mint authority creates a **group mint** with the GroupPointer and TokenGroup extensions, setting a max member count and update authority -2. The GroupPointer references the account that stores group data — typically the mint itself -3. For each member, a separate **member mint** is created with the GroupMemberPointer and TokenGroupMember extensions -4. The TokenGroupMember extension links the member mint to the parent group and assigns a sequential member number -5. Both group and member mints are registered with Light Token for rent-free compressed accounts - ## Use Token Groups With Light Token @@ -40,16 +32,10 @@ Token groups use four related extensions that work in pairs: - - - ### Create Group Mint Create a Token-2022 mint with the GroupPointer and TokenGroup extensions. - - - ```typescript import { Keypair, @@ -126,28 +112,6 @@ const signature = await sendAndConfirmTransaction(rpc, tx, [ ]); ``` - - - -```typescript -import { createMintInterface } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const { mint, transactionSignature } = await createMintInterface( - rpc, payer, payer, null, 0, groupMintKeypair, undefined, TOKEN_2022_PROGRAM_ID -); -``` - - -`createMintInterface` creates and registers a standard Token-2022 mint. To add the GroupPointer and TokenGroup extensions, use the instruction approach in the other tab. - - - - - - - - ### Create Member Mint Create a member mint with the GroupMemberPointer and TokenGroupMember extensions, linking it to the group mint. @@ -213,12 +177,9 @@ const memberTx = new Transaction().add( await sendAndConfirmTransaction(rpc, memberTx, [payer, memberMintKeypair]); ``` - - - -### Register Both Mints With Light Token +### Create Interface PDA for Existing Mints -Register both the group mint and member mint with Light Token to enable rent-free compressed accounts. +Create interface PDAs for both the group mint and member mint with Light Token. ```typescript // Register group mint @@ -239,30 +200,6 @@ const registerTx = new Transaction().add(registerGroupIx, registerMemberIx); await sendAndConfirmTransaction(rpc, registerTx, [payer]); ``` - - - -### Transfer Tokens - -Once mints are registered, transfers work identically to any other Light Token mint. - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, payer.publicKey, mint, amount, owner.publicKey, recipient -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); -} -``` - - - - diff --git a/light-token/extensions/transfer-fees.mdx b/light-token/extensions/transfer-fees.mdx index d917a02..9e7aac1 100644 --- a/light-token/extensions/transfer-fees.mdx +++ b/light-token/extensions/transfer-fees.mdx @@ -12,7 +12,8 @@ import TransferFeesAiPrompt from "/snippets/ai-prompts/extensions/transfer-fees. ## Key Concepts -Fees are expressed in basis points and accumulate in recipient token accounts. A designated withdraw authority can collect the accumulated fees. +The TransferFeeExtension enables automatic fee collection on every token transfer. +Fees accumulate in the recipient token accounts and can be withdrawn by the withdraw authority set on the mint account. Transfer fees are configured with four parameters: @@ -23,21 +24,6 @@ Transfer fees are configured with four parameters: | `transferFeeConfigAuthority` | Authority that can modify fee settings. | | `withdrawWithheldAuthority` | Authority that can collect accumulated fees from recipient accounts. | -During a transfer, the token program calculates the fee as a percentage of the transfer amount (capped by `maximumFee`) -and withholds it in the recipient's token account. With Light Token, both values are zero, so no fees are collected. - -## How It Works - -1. A mint authority creates a Token-2022 mint with the TransferFeeConfig extension -2. The fee basis points and maximum fee are set at initialization -3. On every `transfer_checked` call, the token program withholds the fee from the transferred amount -4. Fees accumulate in recipient token accounts and can be harvested to the mint, then withdrawn by the withdraw authority - - -Light Token requires the transfer fee to be set to **zero basis points** and the maximum fee to **zero**. -You can initialize the extension for compatibility with existing Token-2022 mints, but non-zero fees are not supported. Registration fails if fees are non-zero. - - ## Use TransferFeeConfig With Light Token @@ -47,9 +33,6 @@ You can initialize the extension for compatibility with existing Token-2022 mint - - - ### Create a Token-2022 Mint With Transfer Fees @@ -161,12 +144,9 @@ const { mint, transactionSignature } = await createMintInterface( - - - -### Register an Existing Mint +### Create Interface PDA for Existing Mint -If you already have a Token-2022 mint with a zero-fee TransferFeeConfig, register it with Light Token. +If you already have a Token-2022 mint with a zero-fee TransferFeeConfig, create an interface PDA with Light Token. ```typescript import { LightTokenProgram } from "@lightprotocol/compressed-token"; @@ -179,36 +159,6 @@ const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ }); ``` - - - -### Transfer Tokens - -Transfers work identically to any other Light Token mint. Because the fee is zero, no fees are withheld. - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, - payer.publicKey, - mint, - amount, - owner.publicKey, - recipient -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); -} -``` - - - - - diff --git a/light-token/extensions/transfer-hook.mdx b/light-token/extensions/transfer-hook.mdx index b22687c..40f30ab 100644 --- a/light-token/extensions/transfer-hook.mdx +++ b/light-token/extensions/transfer-hook.mdx @@ -11,7 +11,7 @@ import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import TransferHookAiPrompt from "/snippets/ai-prompts/extensions/transfer-hook.mdx"; -## Key Concepts +## Key Parameters A program address stored on the mint is invoked via CPI on every token transfer to execute custom logic such as transfer restrictions, royalty enforcement, or event emission. @@ -23,15 +23,6 @@ TransferHook is configured with two parameters: | `authority` | Account that can update the transfer hook program address after initialization. | | `programId` | Address of the program invoked via CPI on every transfer. **Must be `PublicKey.default` (nil) for Light Token.** | - -## How It Works - -1. A mint authority creates a Token-2022 mint with the TransferHook extension -2. The hook program address is set at initialization (must be nil for Light Token) -3. On every `transfer_checked` call, the token program invokes the hook program via CPI -4. All accounts from the initial transfer are passed as read-only to the hook program -5. If the hook instruction fails, the entire token transfer reverts - Light Token requires the TransferHook `program_id` to be set to `PublicKey.default` (all zeros). You can initialize the extension for compatibility, but active hooks are not supported. Registration fails if the `program_id` points to a real program. @@ -45,9 +36,6 @@ Light Token requires the TransferHook `program_id` to be set to `PublicKey.defau - - - ### Create a Token-2022 Mint With Transfer Hook @@ -158,12 +146,9 @@ const { mint, transactionSignature } = await createMintInterface( - - - -### Register an Existing Mint +### Create Interface PDA for Existing Mint -If you already have a Token-2022 mint with TransferHook set to a nil `program_id`, register it with Light Token. +If you already have a Token-2022 mint with TransferHook set to a nil `program_id`, create an interface PDA with Light Token. ```typescript import { LightTokenProgram } from "@lightprotocol/compressed-token"; @@ -176,36 +161,6 @@ const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ }); ``` - - - -### Transfer Tokens - -Transfers work identically to any other Light Token mint. Because the hook is disabled, no CPI is invoked during transfers. - -```typescript -import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; - -const instructions = await createTransferInterfaceInstructions( - rpc, - payer.publicKey, - mint, - amount, - owner.publicKey, - recipient -); - -for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer, owner]); -} -``` - - - - - diff --git a/light-token/payments/production-readiness.mdx b/light-token/payments/production-readiness.mdx index 7ded428..e83c30c 100644 --- a/light-token/payments/production-readiness.mdx +++ b/light-token/payments/production-readiness.mdx @@ -22,31 +22,6 @@ Light Token requires a Photon-compatible RPC endpoint for cold account lookups a |:---------|:---------------|:------| | [Helius](https://helius.dev) | Yes | Recommended. Maintains the Photon indexer. | | [Triton](https://triton.one) | Yes | Alternative provider. | -| Self-hosted | Yes | Run the [open-source Photon indexer](https://github.com/helius-labs/photon). | - - -If the Photon indexer is temporarily unavailable, hot accounts continue to work normally. -Cold accounts cannot be loaded until the indexer recovers. - - -### Redundant RPC configuration - -For production reliability, configure multiple RPC endpoints: - -```typescript -import { createRpc } from "@lightprotocol/stateless.js"; - -const primaryRpc = createRpc(process.env.PRIMARY_RPC_URL); -const fallbackRpc = createRpc(process.env.SECONDARY_RPC_URL); - -async function sendWithFallback(fn: (rpc: any) => Promise) { - try { - return await fn(primaryRpc); - } catch { - return await fn(fallbackRpc); - } -} -``` ## Transaction landing @@ -83,15 +58,11 @@ Set your application as the fee payer so users never interact with SOL: ## Pre-launch checklist - [ ] Photon-compatible RPC endpoint configured and tested -- [ ] Redundant RPC endpoint available for failover - [ ] Fee payer wallet funded with sufficient SOL -- [ ] [Cold account loading](/light-token/payments/receive-payments) tested end-to-end - [ ] Error handling covers load failures, tx size limits, and retries - [ ] Confirmation level appropriate for your use case - [ ] [Address verification](/light-token/payments/verify-recipient-address) implemented -- [ ] Monitoring and alerting set up (tx success rates, cold account loading, fee payer balance) -- [ ] [Wrap/unwrap](/light-token/payments/wrap-unwrap) flows tested for CEX interoperability (if applicable) -- [ ] [Wrap/unwrap](/light-token/payments/wrap-unwrap) flows tested for SPL interoperability (if applicable) +- [ ] [Wrap/unwrap](/light-token/payments/wrap-unwrap) flows tested for SPL / Token 2022 interoperability (if applicable) diff --git a/light-token/payments/spend-permissions.mdx b/light-token/payments/spend-permissions.mdx index 63ddf9d..09ecc9a 100644 --- a/light-token/payments/spend-permissions.mdx +++ b/light-token/payments/spend-permissions.mdx @@ -34,6 +34,11 @@ When you approve a delegate, you're authorizing a specific account to transfer t + + + + + @@ -99,6 +104,59 @@ console.log("Delegate:", account.parsed.delegate?.toBase58() ?? "none"); console.log("Delegated amount:", account.parsed.delegatedAmount.toString()); ``` +## Transfer as Delegate + +Once approved, the delegate can transfer tokens on behalf of the owner. The delegate is the transaction authority. Only the delegate and fee payer sign; the owner's signature is not required. + +`transferDelegatedInterface` takes a recipient wallet address and creates the recipient's associated token account internally. + +```typescript +import { transferDelegatedInterface } from "@lightprotocol/compressed-token/unified"; + +const tx = await transferDelegatedInterface( + rpc, + payer, + senderAta, + mint, + recipient.publicKey, // recipient wallet (associated token account created internally) + delegate, // delegate authority (signer) + owner.publicKey, // owner (does not sign) + 200_000, // must be within approved cap +); + +console.log("Delegated transfer:", tx); +``` + + + +`createTransferDelegatedInterfaceInstructions` returns `TransactionInstruction[][]` for manual transaction control. + +```typescript +import { + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createTransferDelegatedInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; + +const instructions = await createTransferDelegatedInterfaceInstructions( + rpc, + payer.publicKey, + mint, + 200_000, + delegate.publicKey, + owner.publicKey, + recipient.publicKey, + 9, // decimals +); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, delegate]); +} +``` + + + ## Revoke a delegate Remove spending permission: diff --git a/snippets/ai-prompts/program-cookbook/transfer-checked.mdx b/snippets/ai-prompts/program-cookbook/transfer-checked.mdx index a94d495..b39a18d 100644 --- a/snippets/ai-prompts/program-cookbook/transfer-checked.mdx +++ b/snippets/ai-prompts/program-cookbook/transfer-checked.mdx @@ -15,6 +15,9 @@ Context: Key CPI struct: \`light_token::instruction::TransferCheckedCpi\` +Note: TransferInterface uses TransferChecked under the hood for Light-to-Light transfers. +Use TransferChecked/TransferCheckedCpi directly only when you need Light-to-Light without interface routing. + ### 1. Index project - Grep \`declare_id|#\[program\]|anchor_lang|Account<|Pubkey|invoke|transfer|decimals|amount\` across src/ - Glob \`**/*.rs\` and \`**/Cargo.toml\` for project structure @@ -73,6 +76,9 @@ Context: Key CPI struct: `light_token::instruction::TransferCheckedCpi` +Note: TransferInterface uses TransferChecked under the hood for Light-to-Light transfers. +Use TransferChecked/TransferCheckedCpi directly only when you need Light-to-Light without interface routing. + ### 1. Index project - Grep `declare_id|#\[program\]|anchor_lang|Account<|Pubkey|invoke|transfer|decimals|amount` across src/ - Glob `**/*.rs` and `**/Cargo.toml` for project structure diff --git a/snippets/ai-prompts/toolkits/payments.mdx b/snippets/ai-prompts/toolkits/payments.mdx index 49eac2d..3eeeebe 100644 --- a/snippets/ai-prompts/toolkits/payments.mdx +++ b/snippets/ai-prompts/toolkits/payments.mdx @@ -18,6 +18,7 @@ SPL → Light Token API mapping: | Operation | SPL | Light Token | | Receive | getOrCreateAssociatedTokenAccount() | createLoadAtaInstructions() / loadAta() | | Transfer | createTransferInstruction() | createTransferInterfaceInstructions() | +| Delegated Transfer | transfer() (delegate signs) | transferDelegatedInterface() | | Get Balance | getAccount() | getAtaInterface() | | Tx History | getSignaturesForAddress() | getSignaturesForOwnerInterface() | | Wrap SPL | N/A | createWrapInstruction() / wrap() | @@ -88,6 +89,7 @@ SPL → Light Token API mapping: | Operation | SPL | Light Token | | Receive | getOrCreateAssociatedTokenAccount() | createLoadAtaInstructions() / loadAta() | | Transfer | createTransferInstruction() | createTransferInterfaceInstructions() | +| Delegated Transfer | transfer() (delegate signs) | transferDelegatedInterface() | | Get Balance | getAccount() | getAtaInterface() | | Tx History | getSignaturesForAddress() | getSignaturesForOwnerInterface() | | Wrap SPL | N/A | createWrapInstruction() / wrap() | diff --git a/snippets/ai-prompts/ts-cookbook/transfer-interface.mdx b/snippets/ai-prompts/ts-cookbook/transfer-interface.mdx index 90717c6..a3d1947 100644 --- a/snippets/ai-prompts/ts-cookbook/transfer-interface.mdx +++ b/snippets/ai-prompts/ts-cookbook/transfer-interface.mdx @@ -12,11 +12,15 @@ Context: - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js -transferInterface() transfers tokens between token accounts (SPL, Token 2022, or Light Token) in a single call. +transferInterface() transfers tokens in a single call. The recipient parameter is a wallet public key. +The SDK derives and creates the destination ATA internally. All transfers use transferChecked under the hood. - Light Token → Light Token: transfers between Light Token accounts - SPL → Light Token: locks SPL tokens in interface PDA, mints to Light Token account - Light Token → SPL: burns Light Token balance, releases SPL tokens from interface PDA +Edge case: for explicit destination token accounts (PDA/program-owned), use transferToAccountInterface() +or createTransferToAccountInterfaceInstructions(). Most integrations should use transferInterface(). + ### 1. Index project - Grep \`@solana/spl-token|Connection|Keypair|transfer|transferInterface\` across src/ - Glob \`**/*.ts\` for project structure @@ -71,11 +75,15 @@ Context: - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js -transferInterface() transfers tokens between token accounts (SPL, Token 2022, or Light Token) in a single call. +transferInterface() transfers tokens in a single call. The recipient parameter is a wallet public key. +The SDK derives and creates the destination ATA internally. All transfers use transferChecked under the hood. - Light Token → Light Token: transfers between Light Token accounts - SPL → Light Token: locks SPL tokens in interface PDA, mints to Light Token account - Light Token → SPL: burns Light Token balance, releases SPL tokens from interface PDA +Edge case: for explicit destination token accounts (PDA/program-owned), use transferToAccountInterface() +or createTransferToAccountInterfaceInstructions(). Most integrations should use transferInterface(). + ### 1. Index project - Grep `@solana/spl-token|Connection|Keypair|transfer|transferInterface` across src/ - Glob `**/*.ts` for project structure diff --git a/snippets/code-samples/code-compare-snippets.jsx b/snippets/code-samples/code-compare-snippets.jsx index b567ec3..5a4ec16 100644 --- a/snippets/code-samples/code-compare-snippets.jsx +++ b/snippets/code-samples/code-compare-snippets.jsx @@ -444,15 +444,16 @@ export const splApproveCode = [ ].join("\n"); export const lightApproveCode = [ - 'import { approve } from "@lightprotocol/compressed-token";', + 'import { approveInterface } from "@lightprotocol/compressed-token";', "", - "const tx = await approve(", + "const tx = await approveInterface(", " rpc,", " payer,", + " tokenAccount,", " mint,", + " delegate,", " amount,", - " owner,", - " delegate", + " owner", ");", ].join("\n"); @@ -469,12 +470,13 @@ export const splRevokeCode = [ ].join("\n"); export const lightRevokeCode = [ - 'import { revoke } from "@lightprotocol/compressed-token";', + 'import { revokeInterface } from "@lightprotocol/compressed-token";', "", - "const tx = await revoke(", + "const tx = await revokeInterface(", " rpc,", " payer,", - " delegatedAccounts,", + " tokenAccount,", + " mint,", " owner", ");", ].join("\n"); diff --git a/snippets/code-snippets/light-token/approve-revoke/approve-action.mdx b/snippets/code-snippets/light-token/approve-revoke/approve-action.mdx index e358f1f..96c13ed 100644 --- a/snippets/code-snippets/light-token/approve-revoke/approve-action.mdx +++ b/snippets/code-snippets/light-token/approve-revoke/approve-action.mdx @@ -4,17 +4,16 @@ import { Keypair } from "@solana/web3.js"; import { createRpc } from "@lightprotocol/stateless.js"; import { createMintInterface, - mintToCompressed, - approve, + createAtaInterface, + getAssociatedTokenAddressInterface, + mintToInterface, + approveInterface, } 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 RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +const rpc = createRpc(RPC_URL); const payer = Keypair.fromSecretKey( new Uint8Array( @@ -24,16 +23,20 @@ const payer = Keypair.fromSecretKey( (async function () { const { mint } = await createMintInterface(rpc, payer, payer, null, 9); - await mintToCompressed(rpc, payer, mint, payer, [{ recipient: payer.publicKey, amount: 1000n }]); + + await createAtaInterface(rpc, payer, mint, payer.publicKey); + const senderAta = getAssociatedTokenAddressInterface(mint, payer.publicKey); + await mintToInterface(rpc, payer, mint, senderAta, payer, 1_000_000_000); const delegate = Keypair.generate(); - const tx = await approve( + const tx = await approveInterface( rpc, payer, + senderAta, mint, - 500, - payer, delegate.publicKey, + 500_000_000, + payer, ); console.log("Tx:", tx); diff --git a/snippets/code-snippets/light-token/approve-revoke/revoke-action.mdx b/snippets/code-snippets/light-token/approve-revoke/revoke-action.mdx index cd3d7cc..6d5a17b 100644 --- a/snippets/code-snippets/light-token/approve-revoke/revoke-action.mdx +++ b/snippets/code-snippets/light-token/approve-revoke/revoke-action.mdx @@ -4,18 +4,17 @@ import { Keypair } from "@solana/web3.js"; import { createRpc } from "@lightprotocol/stateless.js"; import { createMintInterface, - mintToCompressed, - approve, - revoke, + createAtaInterface, + getAssociatedTokenAddressInterface, + mintToInterface, + approveInterface, + revokeInterface, } 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 RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +const rpc = createRpc(RPC_URL); const payer = Keypair.fromSecretKey( new Uint8Array( @@ -25,16 +24,23 @@ const payer = Keypair.fromSecretKey( (async function () { const { mint } = await createMintInterface(rpc, payer, payer, null, 9); - await mintToCompressed(rpc, payer, mint, payer, [{ recipient: payer.publicKey, amount: 1000n }]); - const delegate = Keypair.generate(); - await approve(rpc, payer, mint, 500, payer, delegate.publicKey); + await createAtaInterface(rpc, payer, mint, payer.publicKey); + const senderAta = getAssociatedTokenAddressInterface(mint, payer.publicKey); + await mintToInterface(rpc, payer, mint, senderAta, payer, 1_000_000_000); - const delegatedAccounts = await rpc.getCompressedTokenAccountsByDelegate( + const delegate = Keypair.generate(); + await approveInterface( + rpc, + payer, + senderAta, + mint, delegate.publicKey, - { mint }, + 500_000_000, + payer, ); - const tx = await revoke(rpc, payer, delegatedAccounts.items, payer); + + const tx = await revokeInterface(rpc, payer, senderAta, mint, payer); console.log("Tx:", tx); })(); diff --git a/snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx b/snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx index 18499f3..2107b99 100644 --- a/snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx +++ b/snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx @@ -3,6 +3,7 @@ import { Keypair } from "@solana/web3.js"; import { getAtaInterface } from "@lightprotocol/compressed-token"; import { approveInterface, + transferDelegatedInterface, revokeInterface, } from "@lightprotocol/compressed-token/unified"; import { rpc, payer, setup } from "../setup.js"; @@ -43,19 +44,48 @@ import { rpc, payer, setup } from "../setup.js"; ); console.log(" Account balance:", account.parsed.amount.toString()); - // 3. Owner revokes all delegate permissions + // 3. Delegate transfers 200,000 tokens on behalf of owner + const recipient = Keypair.generate(); + const transferTx = await transferDelegatedInterface( + rpc, + payer, + senderAta, + mint, + recipient.publicKey, + delegate, + payer.publicKey, + 200_000 + ); + console.log("\n3. Delegate transferred 200,000 tokens"); + console.log(" Tx:", transferTx); + + // 4. Verify balances after delegated transfer + const afterTransfer = await getAtaInterface( + rpc, + senderAta, + payer.publicKey, + mint + ); + console.log("\n4. Account status after delegated transfer:"); + console.log( + " Remaining allowance:", + afterTransfer.parsed.delegatedAmount.toString() + ); + console.log(" Account balance:", afterTransfer.parsed.amount.toString()); + + // 5. Owner revokes all delegate permissions const revokeTx = await revokeInterface(rpc, payer, senderAta, mint, payer); - console.log("\n3. Revoked all delegate permissions"); + console.log("\n5. Revoked all delegate permissions"); console.log(" Tx:", revokeTx); - // 4. Verify delegate is removed + // 6. Verify delegate is removed const afterRevoke = await getAtaInterface( rpc, senderAta, payer.publicKey, mint ); - console.log("\n4. Account status after revoke:"); + console.log("\n6. Account status after revoke:"); console.log( " Delegate:", afterRevoke.parsed.delegate?.toBase58() ?? "none" diff --git a/snippets/code-snippets/payments/spend-permissions/delegate-transfer-instruction.mdx b/snippets/code-snippets/payments/spend-permissions/delegate-transfer-instruction.mdx new file mode 100644 index 0000000..818b230 --- /dev/null +++ b/snippets/code-snippets/payments/spend-permissions/delegate-transfer-instruction.mdx @@ -0,0 +1,34 @@ +```typescript +import { + Keypair, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createTransferDelegatedInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint } = await setup(); + + const delegate = Keypair.generate(); + const recipient = Keypair.generate(); + + // Returns TransactionInstruction[][]. Each inner array is one txn. + const instructions = await createTransferDelegatedInterfaceInstructions( + rpc, + payer.publicKey, + mint, + 200_000, + delegate.publicKey, + payer.publicKey, + recipient.publicKey, + 9 + ); + + for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + const sig = await sendAndConfirmTransaction(rpc, tx, [payer, delegate]); + console.log("Tx:", sig); + } +})(); +``` diff --git a/snippets/code-snippets/payments/spend-permissions/delegate-transfer.mdx b/snippets/code-snippets/payments/spend-permissions/delegate-transfer.mdx new file mode 100644 index 0000000..cf10fdd --- /dev/null +++ b/snippets/code-snippets/payments/spend-permissions/delegate-transfer.mdx @@ -0,0 +1,27 @@ +```typescript +import { Keypair } from "@solana/web3.js"; +import { transferDelegatedInterface } from "@lightprotocol/compressed-token/unified"; +import { rpc, payer, setup } from "../setup.js"; + +(async function () { + const { mint, senderAta } = await setup(); + + // Approve a delegate first (see delegate-approve.mdx) + const delegate = Keypair.generate(); + const recipient = Keypair.generate(); + + // Delegate transfers tokens on behalf of the owner + const tx = await transferDelegatedInterface( + rpc, + payer, + senderAta, + mint, + recipient.publicKey, + delegate, + payer.publicKey, + 200_000 + ); + + console.log("Delegated transfer:", tx); +})(); +``` diff --git a/snippets/migration-reference/ts/approve.mdx b/snippets/migration-reference/ts/approve.mdx index 5a7fcad..3dbc3db 100644 --- a/snippets/migration-reference/ts/approve.mdx +++ b/snippets/migration-reference/ts/approve.mdx @@ -1,12 +1,13 @@ ```typescript -import { approve } from "@lightprotocol/compressed-token"; +import { approveInterface } from "@lightprotocol/compressed-token"; -const tx = await approve( +const tx = await approveInterface( rpc, payer, + tokenAccount, mint, + delegate, amount, - owner, - delegate + owner ); ``` diff --git a/snippets/migration-reference/ts/revoke.mdx b/snippets/migration-reference/ts/revoke.mdx index 34f6028..1c0fe9a 100644 --- a/snippets/migration-reference/ts/revoke.mdx +++ b/snippets/migration-reference/ts/revoke.mdx @@ -1,10 +1,11 @@ ```typescript -import { revoke } from "@lightprotocol/compressed-token"; +import { revokeInterface } from "@lightprotocol/compressed-token"; -const tx = await revoke( +const tx = await revokeInterface( rpc, payer, - delegatedAccounts, + tokenAccount, + mint, owner ); ``` From c358c377addc7c0d58b3ad40bcb6311e48174586 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Thu, 19 Mar 2026 23:21:13 +0000 Subject: [PATCH 09/19] lbefore update snippets --- docs.json | 2 +- light-token/extensions/close-mint.mdx | 2 +- light-token/extensions/default-account-state.mdx | 2 +- light-token/extensions/pausable-mint.mdx | 3 +-- light-token/extensions/permanent-delegate.mdx | 2 +- light-token/payments/batch-payments.mdx | 2 -- 6 files changed, 5 insertions(+), 8 deletions(-) diff --git a/docs.json b/docs.json index 141a652..50774ed 100644 --- a/docs.json +++ b/docs.json @@ -33,7 +33,7 @@ ] }, { - "group": "Light Token Program", + "group": "Light Token APIs", "pages": [ "light-token/welcome", { diff --git a/light-token/extensions/close-mint.mdx b/light-token/extensions/close-mint.mdx index b4793ca..be20b6e 100644 --- a/light-token/extensions/close-mint.mdx +++ b/light-token/extensions/close-mint.mdx @@ -13,7 +13,7 @@ import CloseMintAiPrompt from "/snippets/ai-prompts/extensions/close-mint.mdx"; A designated authority can close a mint account and reclaim its rent-exempt lamports after all tokens have been burned and the total supply reaches zero. -MintCloseAuthority mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) for transfers — compressed transfer instructions are not supported. +Set the `compression_only` flag when creating token accounts for this mint. Use `transferInterface` for transfers as usual. ## Key Parameters diff --git a/light-token/extensions/default-account-state.mdx b/light-token/extensions/default-account-state.mdx index 507225c..bafd6e4 100644 --- a/light-token/extensions/default-account-state.mdx +++ b/light-token/extensions/default-account-state.mdx @@ -13,7 +13,7 @@ import DefaultAccountStateAiPrompt from "/snippets/ai-prompts/extensions/default Every new token account created under a mint starts in a specified state, such as frozen, requiring the freeze authority to thaw accounts before holders can transact. -DefaultAccountState mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) for transfers — compressed transfer instructions are not supported. +Set the `compression_only` flag when creating token accounts for this mint. Use `transferInterface` for transfers as usual. ## Key Parameters diff --git a/light-token/extensions/pausable-mint.mdx b/light-token/extensions/pausable-mint.mdx index 02f9fb8..8665da5 100644 --- a/light-token/extensions/pausable-mint.mdx +++ b/light-token/extensions/pausable-mint.mdx @@ -13,8 +13,7 @@ import PausableMintAiPrompt from "/snippets/ai-prompts/extensions/pausable-mint. When paused, all minting, burning, and transfers are blocked until the authority resumes the mint. -Pausable mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) -for transfers. +Set the `compression_only` flag when creating token accounts for this mint. Use `transferInterface` for transfers as usual. ## Key Parameters diff --git a/light-token/extensions/permanent-delegate.mdx b/light-token/extensions/permanent-delegate.mdx index 7745ee1..1961141 100644 --- a/light-token/extensions/permanent-delegate.mdx +++ b/light-token/extensions/permanent-delegate.mdx @@ -13,7 +13,7 @@ import PermanentDelegateAiPrompt from "/snippets/ai-prompts/extensions/permanent A designated authority gains irrevocable transfer and burn rights over every token account for a mint, set once at initialization and enforced permanently. -PermanentDelegate mints require `compression_only` accounts. Use the Light Token interface APIs (`transferInterface`, `createTransferInterfaceInstructions`) for transfers — compressed transfer instructions are not supported. +Set the `compression_only` flag when creating token accounts for this mint. Use `transferInterface` for transfers as usual. ## Key Parameters diff --git a/light-token/payments/batch-payments.mdx b/light-token/payments/batch-payments.mdx index 0045c12..beea2a3 100644 --- a/light-token/payments/batch-payments.mdx +++ b/light-token/payments/batch-payments.mdx @@ -10,8 +10,6 @@ import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillPayments from "/snippets/setup/agent-skill-payments.mdx"; import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; -Send payments to multiple recipients in a single atomic transaction. -
**SPL token -> Light Token Account****Token 2022 / SPL token -> Light Token Account**
  • Transfers SPL tokens to Light Token accounts
  • -
  • SPL tokens are locked in interface PDA
  • +
  • SPL / Token 2022 tokens are locked in interface PDA
  • Tokens are minted to Light Token account
**Light Token -> SPL Account****Light Token -> SPL / Token 2022 Account**
    -
  • Releases SPL tokens from interface PDA to SPL account
  • +
  • Releases SPL / Token 2022 tokens from interface PDA to SPL account
  • Burns tokens in source Light Token account
approve() approveInterface()
**Delegated Transfer**transfer() (delegate signs)transferDelegatedInterface()
**Revoke** revoke()
From bd7e15bc15967aa48cc1f36262ff33287e2b3a53 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Thu, 19 Mar 2026 23:49:50 +0000 Subject: [PATCH 10/19] lbefore update snippet --- light-token/payments/overview.mdx | 7 +++---- light-token/payments/wrap-unwrap.mdx | 16 ---------------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/light-token/payments/overview.mdx b/light-token/payments/overview.mdx index 3a15bce..83c5127 100644 --- a/light-token/payments/overview.mdx +++ b/light-token/payments/overview.mdx @@ -47,9 +47,8 @@ The token standard pays rent-exemption cost for you. To prevent griefing, “ren -You can abstract fees entirely so users never interact with SOL. -- See [fee abstraction](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction) for transaction fees. -- See [gasless transactions](/light-token/wallets/gasless-transactions). +You can abstract fees entirely so users never interact with SOL. See [gasless transactions](/light-token/wallets/gasless-transactions) +to sponsor rent top-ups and transaction fees. ## API Comparison @@ -94,7 +93,7 @@ Learn more about Token-2022 extensions: [Extensions](https://solana.com/docs/tok -### Gasless Transactions +### Fee Abstraction ### Signing diff --git a/light-token/payments/wrap-unwrap.mdx b/light-token/payments/wrap-unwrap.mdx index 8941411..1641df1 100644 --- a/light-token/payments/wrap-unwrap.mdx +++ b/light-token/payments/wrap-unwrap.mdx @@ -159,22 +159,6 @@ await unwrap(rpc, payer, splAta, owner, mint, amount); -## Register an existing SPL mint - -For existing SPL mints like USDC, register the SPL interface PDA once before wrapping: - - - - -`createMintInterface()` does this automatically when creating new mints. -You only need to register manually for mints that already exist on-chain. - - - -For full TypeScript, Rust, and program-level examples, see the -[wrap and unwrap cookbook page](/light-token/cookbook/wrap-unwrap). - - From 3cc577c25fc0712140d312191510ee918792a974 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Fri, 20 Mar 2026 00:51:21 +0000 Subject: [PATCH 11/19] Update extension pages to use snippet imports + regenerate all light-token snippets --- light-token/extensions/close-mint.mdx | 23 +-- .../extensions/default-account-state.mdx | 23 +-- .../extensions/interest-bearing-tokens.mdx | 23 +-- .../metadata-and-metadata-pointer.mdx | 23 +-- light-token/extensions/pausable-mint.mdx | 23 +-- light-token/extensions/permanent-delegate.mdx | 23 +-- light-token/extensions/transfer-fees.mdx | 23 +-- light-token/extensions/transfer-hook.mdx | 23 +-- .../approve-revoke/approve-action.mdx | 28 +-- .../approve-revoke/revoke-action.mdx | 30 +-- .../approve/anchor-program/full-example.mdx | 4 + .../burn/anchor-program/full-example.mdx | 6 +- .../light-token/create-ata/action.mdx | 6 +- .../create-ata/anchor-macro/full-example.mdx | 32 ++-- .../anchor-program/full-example.mdx | 6 +- .../light-token/create-ata/instruction.mdx | 10 +- .../light-token/create-mint/action.mdx | 23 ++- .../create-mint/anchor-macro/full-example.mdx | 39 ++-- .../light-token/create-mint/instruction.mdx | 14 +- .../anchor-macro/full-example.mdx | 26 +-- .../light-token/delegate-transfer/action.mdx | 65 +++++++ .../extensions/close-mint/action.mdx | 91 +++++++++ .../confidential-transfer/action.mdx | 141 ++++++++++++++ .../default-account-state/action.mdx | 92 +++++++++ .../extensions/interest-bearing/action.mdx | 93 +++++++++ .../extensions/metadata-pointer/action.mdx | 120 ++++++++++++ .../extensions/pausable/action.mdx | 89 +++++++++ .../extensions/permanent-delegate/action.mdx | 91 +++++++++ .../extensions/token-groups/action.mdx | 179 ++++++++++++++++++ .../extensions/transfer-fees/action.mdx | 94 +++++++++ .../extensions/transfer-hook/action.mdx | 93 +++++++++ .../light-token/load-ata/action.mdx | 19 +- .../light-token/load-ata/instruction.mdx | 30 +-- .../light-token/mint-to/action.mdx | 20 +- .../mint-to/anchor-program/full-example.mdx | 6 +- .../light-token/mint-to/instruction.mdx | 12 +- .../revoke/anchor-program/full-example.mdx | 5 + .../anchor-program/full-example.mdx | 6 +- .../light-token/transfer-interface/action.mdx | 29 ++- .../anchor-program/full-example.mdx | 19 +- .../transfer-interface/instruction.mdx | 11 +- .../light-token/unwrap/action.mdx | 39 ++-- .../light-token/unwrap/instruction.mdx | 39 ++-- .../code-snippets/light-token/wrap/action.mdx | 44 +++-- .../light-token/wrap/instruction.mdx | 47 +++-- 45 files changed, 1502 insertions(+), 380 deletions(-) create mode 100644 snippets/code-snippets/light-token/delegate-transfer/action.mdx create mode 100644 snippets/code-snippets/light-token/extensions/close-mint/action.mdx create mode 100644 snippets/code-snippets/light-token/extensions/confidential-transfer/action.mdx create mode 100644 snippets/code-snippets/light-token/extensions/default-account-state/action.mdx create mode 100644 snippets/code-snippets/light-token/extensions/interest-bearing/action.mdx create mode 100644 snippets/code-snippets/light-token/extensions/metadata-pointer/action.mdx create mode 100644 snippets/code-snippets/light-token/extensions/pausable/action.mdx create mode 100644 snippets/code-snippets/light-token/extensions/permanent-delegate/action.mdx create mode 100644 snippets/code-snippets/light-token/extensions/token-groups/action.mdx create mode 100644 snippets/code-snippets/light-token/extensions/transfer-fees/action.mdx create mode 100644 snippets/code-snippets/light-token/extensions/transfer-hook/action.mdx diff --git a/light-token/extensions/close-mint.mdx b/light-token/extensions/close-mint.mdx index be20b6e..a4a93c5 100644 --- a/light-token/extensions/close-mint.mdx +++ b/light-token/extensions/close-mint.mdx @@ -9,6 +9,7 @@ import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import CloseMintAiPrompt from "/snippets/ai-prompts/extensions/close-mint.mdx"; +import CloseMintAction from "/snippets/code-snippets/light-token/extensions/close-mint/action.mdx"; A designated authority can close a mint account and reclaim its rent-exempt lamports after all tokens have been burned and the total supply reaches zero. @@ -114,27 +115,7 @@ const signature = await sendAndConfirmTransaction(rpc, tx, [ - -```typescript -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMintInterface } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const { mint, transactionSignature } = await createMintInterface( - rpc, - payer, - payer, - null, - 9, - mintKeypair, - undefined, - TOKEN_2022_PROGRAM_ID -); -``` + `createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the MintCloseAuthority extension, use the instruction approach shown in the other tab. diff --git a/light-token/extensions/default-account-state.mdx b/light-token/extensions/default-account-state.mdx index bafd6e4..6ae809c 100644 --- a/light-token/extensions/default-account-state.mdx +++ b/light-token/extensions/default-account-state.mdx @@ -9,6 +9,7 @@ import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import DefaultAccountStateAiPrompt from "/snippets/ai-prompts/extensions/default-account-state.mdx"; +import DefaultAccountStateAction from "/snippets/code-snippets/light-token/extensions/default-account-state/action.mdx"; Every new token account created under a mint starts in a specified state, such as frozen, requiring the freeze authority to thaw accounts before holders can transact. @@ -116,27 +117,7 @@ const signature = await sendAndConfirmTransaction(rpc, tx, [ - -```typescript -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMintInterface } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const { mint, transactionSignature } = await createMintInterface( - rpc, - payer, - payer, - null, - 9, - mintKeypair, - undefined, - TOKEN_2022_PROGRAM_ID -); -``` + `createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the DefaultAccountState extension, use the instruction approach shown in the other tab. diff --git a/light-token/extensions/interest-bearing-tokens.mdx b/light-token/extensions/interest-bearing-tokens.mdx index d6b586b..8398d2e 100644 --- a/light-token/extensions/interest-bearing-tokens.mdx +++ b/light-token/extensions/interest-bearing-tokens.mdx @@ -9,6 +9,7 @@ import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import InterestBearingTokensAiPrompt from "/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx"; +import InterestBearingAction from "/snippets/code-snippets/light-token/extensions/interest-bearing/action.mdx"; ## Key Parameters @@ -117,27 +118,7 @@ const signature = await sendAndConfirmTransaction(rpc, tx, [ - -```typescript -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMintInterface } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const { mint, transactionSignature } = await createMintInterface( - rpc, - payer, - payer, - null, - 9, - mintKeypair, - undefined, - TOKEN_2022_PROGRAM_ID -); -``` + `createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the InterestBearingConfig extension, use the instruction approach shown in the other tab. diff --git a/light-token/extensions/metadata-and-metadata-pointer.mdx b/light-token/extensions/metadata-and-metadata-pointer.mdx index 4df245e..eafbf14 100644 --- a/light-token/extensions/metadata-and-metadata-pointer.mdx +++ b/light-token/extensions/metadata-and-metadata-pointer.mdx @@ -9,6 +9,7 @@ import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import MetadataAndMetadataPointerAiPrompt from "/snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx"; +import MetadataPointerAction from "/snippets/code-snippets/light-token/extensions/metadata-pointer/action.mdx"; MetadataPointer tells clients where to find a mint's metadata. TokenMetadata removes the need for a separate metadata account. @@ -147,27 +148,7 @@ const signature = await sendAndConfirmTransaction(rpc, tx, [ - -```typescript -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMintInterface } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const { mint, transactionSignature } = await createMintInterface( - rpc, - payer, - payer, - null, - 9, - mintKeypair, - undefined, - TOKEN_2022_PROGRAM_ID -); -``` + `createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the MetadataPointer and TokenMetadata extensions, use the instruction approach shown in the other tab. diff --git a/light-token/extensions/pausable-mint.mdx b/light-token/extensions/pausable-mint.mdx index 8665da5..d9c20a7 100644 --- a/light-token/extensions/pausable-mint.mdx +++ b/light-token/extensions/pausable-mint.mdx @@ -9,6 +9,7 @@ import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import PausableMintAiPrompt from "/snippets/ai-prompts/extensions/pausable-mint.mdx"; +import PausableAction from "/snippets/code-snippets/light-token/extensions/pausable/action.mdx"; When paused, all minting, burning, and transfers are blocked until the authority resumes the mint. @@ -115,27 +116,7 @@ const signature = await sendAndConfirmTransaction(rpc, tx, [ - -```typescript -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMintInterface } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const { mint, transactionSignature } = await createMintInterface( - rpc, - payer, - payer, - null, - 9, - mintKeypair, - undefined, - TOKEN_2022_PROGRAM_ID -); -``` + `createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the Pausable extension, use the instruction approach shown in the other tab. diff --git a/light-token/extensions/permanent-delegate.mdx b/light-token/extensions/permanent-delegate.mdx index 1961141..73bc6d7 100644 --- a/light-token/extensions/permanent-delegate.mdx +++ b/light-token/extensions/permanent-delegate.mdx @@ -9,6 +9,7 @@ import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import PermanentDelegateAiPrompt from "/snippets/ai-prompts/extensions/permanent-delegate.mdx"; +import PermanentDelegateAction from "/snippets/code-snippets/light-token/extensions/permanent-delegate/action.mdx"; A designated authority gains irrevocable transfer and burn rights over every token account for a mint, set once at initialization and enforced permanently. @@ -114,27 +115,7 @@ const signature = await sendAndConfirmTransaction(rpc, tx, [ - -```typescript -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMintInterface } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const { mint, transactionSignature } = await createMintInterface( - rpc, - payer, - payer, - null, - 9, - mintKeypair, - undefined, - TOKEN_2022_PROGRAM_ID -); -``` + `createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the PermanentDelegate extension, use the instruction approach shown in the other tab. diff --git a/light-token/extensions/transfer-fees.mdx b/light-token/extensions/transfer-fees.mdx index 9e7aac1..9cf89bb 100644 --- a/light-token/extensions/transfer-fees.mdx +++ b/light-token/extensions/transfer-fees.mdx @@ -9,6 +9,7 @@ import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import TransferFeesAiPrompt from "/snippets/ai-prompts/extensions/transfer-fees.mdx"; +import TransferFeeAction from "/snippets/code-snippets/light-token/extensions/transfer-fees/action.mdx"; ## Key Concepts @@ -115,27 +116,7 @@ const signature = await sendAndConfirmTransaction(rpc, tx, [ - -```typescript -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMintInterface } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const { mint, transactionSignature } = await createMintInterface( - rpc, - payer, - payer, - null, - 9, - mintKeypair, - undefined, - TOKEN_2022_PROGRAM_ID -); -``` + `createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the TransferFeeConfig extension, use the instruction approach shown in the other tab. diff --git a/light-token/extensions/transfer-hook.mdx b/light-token/extensions/transfer-hook.mdx index 40f30ab..2c7edff 100644 --- a/light-token/extensions/transfer-hook.mdx +++ b/light-token/extensions/transfer-hook.mdx @@ -9,6 +9,7 @@ import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; import TransferHookAiPrompt from "/snippets/ai-prompts/extensions/transfer-hook.mdx"; +import TransferHookAction from "/snippets/code-snippets/light-token/extensions/transfer-hook/action.mdx"; ## Key Parameters @@ -117,27 +118,7 @@ const signature = await sendAndConfirmTransaction(rpc, tx, [ - -```typescript -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMintInterface } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const { mint, transactionSignature } = await createMintInterface( - rpc, - payer, - payer, - null, - 9, - mintKeypair, - undefined, - TOKEN_2022_PROGRAM_ID -); -``` + `createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the TransferHook extension, use the instruction approach shown in the other tab. diff --git a/snippets/code-snippets/light-token/approve-revoke/approve-action.mdx b/snippets/code-snippets/light-token/approve-revoke/approve-action.mdx index 96c13ed..8fc9b23 100644 --- a/snippets/code-snippets/light-token/approve-revoke/approve-action.mdx +++ b/snippets/code-snippets/light-token/approve-revoke/approve-action.mdx @@ -4,30 +4,32 @@ import { Keypair } from "@solana/web3.js"; import { createRpc } from "@lightprotocol/stateless.js"; import { createMintInterface, - createAtaInterface, + mintToCompressed, getAssociatedTokenAddressInterface, - mintToInterface, - approveInterface, } from "@lightprotocol/compressed-token"; +import { approveInterface } from "@lightprotocol/compressed-token/unified"; import { homedir } from "os"; import { readFileSync } from "fs"; -const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; -const rpc = createRpc(RPC_URL); +// 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")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { const { mint } = await createMintInterface(rpc, payer, payer, null, 9); + await mintToCompressed(rpc, payer, mint, payer, [ + { recipient: payer.publicKey, amount: 1000n }, + ]); - await createAtaInterface(rpc, payer, mint, payer.publicKey); const senderAta = getAssociatedTokenAddressInterface(mint, payer.publicKey); - await mintToInterface(rpc, payer, mint, senderAta, payer, 1_000_000_000); - const delegate = Keypair.generate(); const tx = await approveInterface( rpc, @@ -35,10 +37,12 @@ const payer = Keypair.fromSecretKey( senderAta, mint, delegate.publicKey, - 500_000_000, - payer, + 500_000, + payer ); + console.log("Approved delegate:", delegate.publicKey.toBase58()); + console.log("Allowance: 500,000 tokens"); console.log("Tx:", tx); })(); ``` diff --git a/snippets/code-snippets/light-token/approve-revoke/revoke-action.mdx b/snippets/code-snippets/light-token/approve-revoke/revoke-action.mdx index 6d5a17b..1dc888d 100644 --- a/snippets/code-snippets/light-token/approve-revoke/revoke-action.mdx +++ b/snippets/code-snippets/light-token/approve-revoke/revoke-action.mdx @@ -4,31 +4,35 @@ import { Keypair } from "@solana/web3.js"; import { createRpc } from "@lightprotocol/stateless.js"; import { createMintInterface, - createAtaInterface, + mintToCompressed, getAssociatedTokenAddressInterface, - mintToInterface, +} from "@lightprotocol/compressed-token"; +import { approveInterface, revokeInterface, -} from "@lightprotocol/compressed-token"; +} from "@lightprotocol/compressed-token/unified"; import { homedir } from "os"; import { readFileSync } from "fs"; -const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; -const rpc = createRpc(RPC_URL); +// 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")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { const { mint } = await createMintInterface(rpc, payer, payer, null, 9); + await mintToCompressed(rpc, payer, mint, payer, [ + { recipient: payer.publicKey, amount: 1000n }, + ]); - await createAtaInterface(rpc, payer, mint, payer.publicKey); const senderAta = getAssociatedTokenAddressInterface(mint, payer.publicKey); - await mintToInterface(rpc, payer, mint, senderAta, payer, 1_000_000_000); - const delegate = Keypair.generate(); await approveInterface( rpc, @@ -36,12 +40,14 @@ const payer = Keypair.fromSecretKey( senderAta, mint, delegate.publicKey, - 500_000_000, - payer, + 500_000, + payer ); + console.log("Approved delegate:", delegate.publicKey.toBase58()); const tx = await revokeInterface(rpc, payer, senderAta, mint, payer); + console.log("Revoked all delegate permissions"); console.log("Tx:", tx); })(); ``` diff --git a/snippets/code-snippets/light-token/approve/anchor-program/full-example.mdx b/snippets/code-snippets/light-token/approve/anchor-program/full-example.mdx index ef0eca9..91bb856 100644 --- a/snippets/code-snippets/light-token/approve/anchor-program/full-example.mdx +++ b/snippets/code-snippets/light-token/approve/anchor-program/full-example.mdx @@ -18,6 +18,7 @@ pub mod light_token_anchor_approve { owner: ctx.accounts.owner.to_account_info(), system_program: ctx.accounts.system_program.to_account_info(), amount, + fee_payer: ctx.accounts.fee_payer.to_account_info(), } .invoke()?; Ok(()) @@ -34,6 +35,8 @@ pub struct ApproveAccounts<'info> { /// CHECK: Validated by light-token CPI pub delegate: AccountInfo<'info>, pub owner: Signer<'info>, + #[account(mut)] + pub fee_payer: Signer<'info>, pub system_program: Program<'info, System>, } ``` @@ -66,6 +69,7 @@ async fn test_approve() { token_account: env.associated_token_account, delegate: delegate.pubkey(), owner: env.payer.pubkey(), + fee_payer: env.payer.pubkey(), system_program: system_program::ID, } .to_account_metas(Some(true)), diff --git a/snippets/code-snippets/light-token/burn/anchor-program/full-example.mdx b/snippets/code-snippets/light-token/burn/anchor-program/full-example.mdx index e305437..8c2a8c4 100644 --- a/snippets/code-snippets/light-token/burn/anchor-program/full-example.mdx +++ b/snippets/code-snippets/light-token/burn/anchor-program/full-example.mdx @@ -18,8 +18,7 @@ pub mod light_token_anchor_burn { amount, authority: ctx.accounts.authority.to_account_info(), system_program: ctx.accounts.system_program.to_account_info(), - max_top_up: None, - fee_payer: None, + fee_payer: ctx.accounts.fee_payer.to_account_info(), } .invoke()?; Ok(()) @@ -37,6 +36,8 @@ pub struct BurnAccounts<'info> { #[account(mut)] pub mint: AccountInfo<'info>, pub authority: Signer<'info>, + #[account(mut)] + pub fee_payer: Signer<'info>, pub system_program: Program<'info, System>, } ``` @@ -67,6 +68,7 @@ async fn test_burn() { source: env.associated_token_account, mint: env.mint_pda, authority: env.payer.pubkey(), + fee_payer: env.payer.pubkey(), system_program: system_program::ID, } .to_account_metas(Some(true)), diff --git a/snippets/code-snippets/light-token/create-ata/action.mdx b/snippets/code-snippets/light-token/create-ata/action.mdx index c971fcf..8bbe823 100644 --- a/snippets/code-snippets/light-token/create-ata/action.mdx +++ b/snippets/code-snippets/light-token/create-ata/action.mdx @@ -10,10 +10,10 @@ 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); +// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +// const rpc = createRpc(RPC_URL); // localnet: -// const rpc = createRpc(); +const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( diff --git a/snippets/code-snippets/light-token/create-ata/anchor-macro/full-example.mdx b/snippets/code-snippets/light-token/create-ata/anchor-macro/full-example.mdx index f8d20b9..89b73bc 100644 --- a/snippets/code-snippets/light-token/create-ata/anchor-macro/full-example.mdx +++ b/snippets/code-snippets/light-token/create-ata/anchor-macro/full-example.mdx @@ -3,11 +3,11 @@ #![allow(deprecated)] use anchor_lang::prelude::*; -use light_compressible::CreateAccountsProof; -use light_sdk::derive_light_cpi_signer; -use light_sdk_macros::{light_program, LightAccounts}; -use light_sdk_types::{CpiSigner, LIGHT_TOKEN_PROGRAM_ID}; -use light_token::instruction::{COMPRESSIBLE_CONFIG_V1, RENT_SPONSOR as LIGHT_TOKEN_RENT_SPONSOR}; +use light_account::{ + derive_light_cpi_signer, light_program, CreateAccountsProof, CpiSigner, LightAccounts, + LIGHT_TOKEN_PROGRAM_ID, +}; +use light_token::instruction::{LIGHT_TOKEN_CONFIG, LIGHT_TOKEN_RENT_SPONSOR}; declare_id!("CLsn9MTFv97oMTsujRoQAw1u2rSm2HnKtGuWUbbc8Jfn"); @@ -31,7 +31,6 @@ pub mod light_token_macro_create_associated_token_account { #[derive(AnchorSerialize, AnchorDeserialize, Clone)] pub struct CreateAssociatedTokenAccountParams { pub create_accounts_proof: CreateAccountsProof, - pub associated_token_account_bump: u8, } #[derive(Accounts, LightAccounts)] @@ -48,12 +47,12 @@ pub struct CreateAssociatedTokenAccount<'info> { /// CHECK: Validated by light_account macro #[account(mut)] - #[light_account(init, associated_token::authority = associated_token_account_owner, associated_token::mint = associated_token_account_mint, associated_token::bump = params.associated_token_account_bump)] + #[light_account(init, associated_token::authority = associated_token_account_owner, associated_token::mint = associated_token_account_mint)] pub associated_token_account: UncheckedAccount<'info>, /// CHECK: Validated by address constraint - #[account(address = COMPRESSIBLE_CONFIG_V1)] - pub light_token_compressible_config: AccountInfo<'info>, + #[account(address = LIGHT_TOKEN_CONFIG)] + pub light_token_config: AccountInfo<'info>, /// CHECK: Validated by address constraint #[account(mut, address = LIGHT_TOKEN_RENT_SPONSOR)] @@ -74,8 +73,8 @@ use light_program_test::{ program_test::{setup_mock_program_data, LightProgramTest}, ProgramTestConfig, Rpc, }; -use light_sdk_types::LIGHT_TOKEN_PROGRAM_ID; -use light_token::instruction::{COMPRESSIBLE_CONFIG_V1, RENT_SPONSOR}; +use light_account::{derive_rent_sponsor_pda, LIGHT_TOKEN_PROGRAM_ID}; +use light_token::instruction::{LIGHT_TOKEN_CONFIG, LIGHT_TOKEN_RENT_SPONSOR}; use solana_instruction::Instruction; use solana_signer::Signer; use test_utils::create_mint; @@ -95,11 +94,13 @@ async fn test_create_associated_token_account() { let program_data_pda = setup_mock_program_data(&mut rpc, &payer, &program_id); + let (rent_sponsor, _) = derive_rent_sponsor_pda(&program_id); + let (init_config_ix, _config_pda) = InitializeRentFreeConfig::new( &program_id, &payer.pubkey(), &program_data_pda, - RENT_SPONSOR, + rent_sponsor, payer.pubkey(), ) .build(); @@ -114,7 +115,7 @@ async fn test_create_associated_token_account() { let associated_token_account_owner = payer.pubkey(); // Derive the associated token account address using Light Token SDK's derivation - let (associated_token_account, associated_token_account_bump) = light_token::instruction::derive_token_ata(&associated_token_account_owner, &mint); + let associated_token_account = light_token::instruction::derive_token_ata(&associated_token_account_owner, &mint); // Get proof (no PDA accounts for associated token account-only instruction) let proof_result = get_create_accounts_proof(&rpc, &program_id, vec![]) @@ -127,8 +128,8 @@ async fn test_create_associated_token_account() { associated_token_account_mint: mint, associated_token_account_owner, associated_token_account, - light_token_compressible_config: COMPRESSIBLE_CONFIG_V1, - light_token_rent_sponsor: RENT_SPONSOR, + light_token_config: LIGHT_TOKEN_CONFIG, + light_token_rent_sponsor: LIGHT_TOKEN_RENT_SPONSOR, light_token_program: LIGHT_TOKEN_PROGRAM_ID.into(), system_program: solana_sdk::system_program::ID, }; @@ -136,7 +137,6 @@ async fn test_create_associated_token_account() { let instruction_data = light_token_macro_create_associated_token_account::instruction::CreateAssociatedTokenAccount { params: CreateAssociatedTokenAccountParams { create_accounts_proof: proof_result.create_accounts_proof, - associated_token_account_bump, }, }; diff --git a/snippets/code-snippets/light-token/create-ata/anchor-program/full-example.mdx b/snippets/code-snippets/light-token/create-ata/anchor-program/full-example.mdx index 6a63b45..86019ec 100644 --- a/snippets/code-snippets/light-token/create-ata/anchor-program/full-example.mdx +++ b/snippets/code-snippets/light-token/create-ata/anchor-program/full-example.mdx @@ -11,13 +11,12 @@ declare_id!("35MukgdfpNUbPMhTmEk63ECV8vjgpNVFRH9nP8ovMN58"); pub mod light_token_anchor_create_associated_token_account { use super::*; - pub fn create_associated_token_account(ctx: Context, bump: u8, idempotent: bool) -> Result<()> { + pub fn create_associated_token_account(ctx: Context, idempotent: bool) -> Result<()> { let cpi = CreateAssociatedAccountCpi { payer: ctx.accounts.payer.to_account_info(), owner: ctx.accounts.owner.to_account_info(), mint: ctx.accounts.mint.to_account_info(), ata: ctx.accounts.associated_token_account.to_account_info(), - bump, }; if idempotent { @@ -138,7 +137,7 @@ async fn test_create_associated_token_account() { // You can use light, spl, t22 mints to create a light token associated token account. // Derive associated token account address and bump - let (associated_token_account, associated_token_account_bump) = derive_token_ata(&payer.pubkey(), &mint_pda); + let associated_token_account = derive_token_ata(&payer.pubkey(), &mint_pda); // Call the anchor program to create associated token account let compressible_config = config_pda(); @@ -158,7 +157,6 @@ async fn test_create_associated_token_account() { } .to_account_metas(Some(true)), data: CreateAssociatedTokenAccount { - bump: associated_token_account_bump, idempotent: false, } .data(), diff --git a/snippets/code-snippets/light-token/create-ata/instruction.mdx b/snippets/code-snippets/light-token/create-ata/instruction.mdx index c507ff0..55dea6d 100644 --- a/snippets/code-snippets/light-token/create-ata/instruction.mdx +++ b/snippets/code-snippets/light-token/create-ata/instruction.mdx @@ -5,7 +5,7 @@ import { Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; -import { createRpc, LIGHT_TOKEN_PROGRAM_ID } from "@lightprotocol/stateless.js"; +import { createRpc, CTOKEN_PROGRAM_ID } from "@lightprotocol/stateless.js"; import { createMintInterface, createAssociatedTokenAccountInterfaceInstruction, @@ -22,8 +22,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -32,7 +32,7 @@ const payer = Keypair.fromSecretKey( const owner = Keypair.generate(); const associatedToken = getAssociatedTokenAddressInterface( mint, - owner.publicKey, + owner.publicKey ); const ix = createAssociatedTokenAccountInterfaceInstruction( @@ -40,7 +40,7 @@ const payer = Keypair.fromSecretKey( associatedToken, owner.publicKey, mint, - LIGHT_TOKEN_PROGRAM_ID, + CTOKEN_PROGRAM_ID ); const tx = new Transaction().add(ix); diff --git a/snippets/code-snippets/light-token/create-mint/action.mdx b/snippets/code-snippets/light-token/create-mint/action.mdx index 24a856a..0607d20 100644 --- a/snippets/code-snippets/light-token/create-mint/action.mdx +++ b/snippets/code-snippets/light-token/create-mint/action.mdx @@ -2,15 +2,18 @@ import "dotenv/config"; import { Keypair } from "@solana/web3.js"; import { createRpc } from "@lightprotocol/stateless.js"; -import { createMintInterface, createTokenMetadata } from "@lightprotocol/compressed-token"; +import { + createMintInterface, + createTokenMetadata, +} 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); +// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +// const rpc = createRpc(RPC_URL); // localnet: -// const rpc = createRpc(); +const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( @@ -25,10 +28,14 @@ const payer = Keypair.fromSecretKey( payer, null, 9, - undefined, - undefined, - undefined, - createTokenMetadata("Example Token", "EXT", "https://example.com/metadata.json") + undefined, // keypair + undefined, // confirmOptions (default) + undefined, // programId (CTOKEN_PROGRAM_ID) + createTokenMetadata( + "Example Token", + "EXT", + "https://example.com/metadata.json" + ) ); console.log("Mint:", mint.toBase58()); diff --git a/snippets/code-snippets/light-token/create-mint/anchor-macro/full-example.mdx b/snippets/code-snippets/light-token/create-mint/anchor-macro/full-example.mdx index 25a7c0b..cd4f5a0 100644 --- a/snippets/code-snippets/light-token/create-mint/anchor-macro/full-example.mdx +++ b/snippets/code-snippets/light-token/create-mint/anchor-macro/full-example.mdx @@ -3,10 +3,9 @@ #![allow(deprecated)] use anchor_lang::prelude::*; -use light_compressible::CreateAccountsProof; -use light_sdk::derive_light_cpi_signer; -use light_sdk_macros::{light_program, LightAccounts}; -use light_sdk_types::CpiSigner; +use light_account::{ + derive_light_cpi_signer, light_program, CreateAccountsProof, CpiSigner, LightAccounts, +}; declare_id!("HVmVqSJyMejBeUigePMSfX4aENJzCGHNxAJuT2PDMPRx"); @@ -59,12 +58,12 @@ pub struct CreateMint<'info> { /// CHECK: Compression config PDA pub compression_config: AccountInfo<'info>, - /// CHECK: Light Token compressible config - pub light_token_compressible_config: AccountInfo<'info>, + /// CHECK: Light Token config + pub light_token_config: AccountInfo<'info>, /// CHECK: Rent sponsor #[account(mut)] - pub rent_sponsor: AccountInfo<'info>, + pub light_token_rent_sponsor: AccountInfo<'info>, /// CHECK: Light Token program pub light_token_program: AccountInfo<'info>, @@ -108,12 +107,12 @@ pub struct CreateMintWithMetadata<'info> { /// CHECK: Compression config PDA pub compression_config: AccountInfo<'info>, - /// CHECK: Light Token compressible config - pub light_token_compressible_config: AccountInfo<'info>, + /// CHECK: Light Token config + pub light_token_config: AccountInfo<'info>, /// CHECK: Rent sponsor #[account(mut)] - pub rent_sponsor: AccountInfo<'info>, + pub light_token_rent_sponsor: AccountInfo<'info>, /// CHECK: Light Token program pub light_token_program: AccountInfo<'info>, @@ -156,8 +155,8 @@ use light_program_test::{ program_test::{setup_mock_program_data, LightProgramTest}, ProgramTestConfig, Rpc, }; -use light_sdk_types::LIGHT_TOKEN_PROGRAM_ID; -use light_token::instruction::{find_mint_address, COMPRESSIBLE_CONFIG_V1, RENT_SPONSOR}; +use light_account::{derive_rent_sponsor_pda, LIGHT_TOKEN_PROGRAM_ID}; +use light_token::instruction::{find_mint_address, LIGHT_TOKEN_CONFIG, LIGHT_TOKEN_RENT_SPONSOR}; use solana_instruction::Instruction; use solana_keypair::Keypair; use solana_pubkey::Pubkey; @@ -176,11 +175,13 @@ async fn setup() -> (light_program_test::LightProgramTest, Keypair, Pubkey, Pubk let program_data_pda = setup_mock_program_data(&mut rpc, &payer, &program_id); + let (rent_sponsor, _) = derive_rent_sponsor_pda(&program_id); + let (init_config_ix, config_pda) = InitializeRentFreeConfig::new( &program_id, &payer.pubkey(), &program_data_pda, - RENT_SPONSOR, + rent_sponsor, payer.pubkey(), ) .build(); @@ -219,10 +220,10 @@ async fn test_create_mint() { mint_signer: mint_signer_pda, mint: mint_pda, compression_config: config_pda, - light_token_compressible_config: COMPRESSIBLE_CONFIG_V1, - rent_sponsor: RENT_SPONSOR, + light_token_config: LIGHT_TOKEN_CONFIG, + light_token_rent_sponsor: LIGHT_TOKEN_RENT_SPONSOR, light_token_program: LIGHT_TOKEN_PROGRAM_ID.into(), - light_token_cpi_authority: light_token_types::CPI_AUTHORITY_PDA.into(), + light_token_cpi_authority: light_token::constants::LIGHT_TOKEN_CPI_AUTHORITY, system_program: solana_sdk::system_program::ID, }; @@ -291,10 +292,10 @@ async fn test_create_mint_with_metadata() { mint_signer: mint_signer_pda, mint: mint_pda, compression_config: config_pda, - light_token_compressible_config: COMPRESSIBLE_CONFIG_V1, - rent_sponsor: RENT_SPONSOR, + light_token_config: LIGHT_TOKEN_CONFIG, + light_token_rent_sponsor: LIGHT_TOKEN_RENT_SPONSOR, light_token_program: LIGHT_TOKEN_PROGRAM_ID.into(), - light_token_cpi_authority: light_token_types::CPI_AUTHORITY_PDA.into(), + light_token_cpi_authority: light_token::constants::LIGHT_TOKEN_CPI_AUTHORITY, system_program: solana_sdk::system_program::ID, }; diff --git a/snippets/code-snippets/light-token/create-mint/instruction.mdx b/snippets/code-snippets/light-token/create-mint/instruction.mdx index 9789b97..000a6cf 100644 --- a/snippets/code-snippets/light-token/create-mint/instruction.mdx +++ b/snippets/code-snippets/light-token/create-mint/instruction.mdx @@ -25,7 +25,7 @@ const COMPRESSED_MINT_SEED = Buffer.from("compressed_mint"); function findMintAddress(mintSigner: PublicKey): [PublicKey, number] { return PublicKey.findProgramAddressSync( [COMPRESSED_MINT_SEED, mintSigner.toBuffer()], - CTOKEN_PROGRAM_ID, + CTOKEN_PROGRAM_ID ); } @@ -37,8 +37,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -49,7 +49,7 @@ const payer = Keypair.fromSecretKey( const validityProof = await rpc.getValidityProofV2( [], - [{ address: mintPda.toBytes(), treeInfo: addressTreeInfo }], + [{ address: mintPda.toBytes(), treeInfo: addressTreeInfo }] ); const ix = createMintInstruction( @@ -64,13 +64,13 @@ const payer = Keypair.fromSecretKey( createTokenMetadata( "Example Token", "EXT", - "https://example.com/metadata.json", - ), + "https://example.com/metadata.json" + ) ); const tx = new Transaction().add( ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 }), - ix, + ix ); const signature = await sendAndConfirmTransaction(rpc, tx, [ payer, diff --git a/snippets/code-snippets/light-token/create-token-account/anchor-macro/full-example.mdx b/snippets/code-snippets/light-token/create-token-account/anchor-macro/full-example.mdx index e716453..6287b23 100644 --- a/snippets/code-snippets/light-token/create-token-account/anchor-macro/full-example.mdx +++ b/snippets/code-snippets/light-token/create-token-account/anchor-macro/full-example.mdx @@ -3,11 +3,10 @@ #![allow(deprecated)] use anchor_lang::prelude::*; -use light_compressible::CreateAccountsProof; -use light_sdk::derive_light_cpi_signer; -use light_sdk_macros::{light_program, LightAccounts}; -use light_sdk_types::CpiSigner; -use light_token::instruction::{COMPRESSIBLE_CONFIG_V1, RENT_SPONSOR as LIGHT_TOKEN_RENT_SPONSOR}; +use light_account::{ + derive_light_cpi_signer, light_program, CreateAccountsProof, CpiSigner, LightAccounts, +}; +use light_token::instruction::{LIGHT_TOKEN_CONFIG, LIGHT_TOKEN_RENT_SPONSOR}; declare_id!("9p5BUDtVmRRJqp2sN73ZUZDbaYtYvEWuxzrHH3A2ni9y"); @@ -47,16 +46,17 @@ pub struct CreateTokenVault<'info> { )] #[light_account( init, - token::authority = [VAULT_SEED, self.mint.key()], + token::seeds = [VAULT_SEED, self.mint.key()], token::mint = mint, token::owner = vault_authority, + token::owner_seeds = [VAULT_AUTH_SEED], token::bump = params.vault_bump )] pub vault: UncheckedAccount<'info>, /// CHECK: Validated by address constraint - #[account(address = COMPRESSIBLE_CONFIG_V1)] - pub light_token_compressible_config: AccountInfo<'info>, + #[account(address = LIGHT_TOKEN_CONFIG)] + pub light_token_config: AccountInfo<'info>, /// CHECK: Validated by address constraint #[account(mut, address = LIGHT_TOKEN_RENT_SPONSOR)] @@ -104,11 +104,11 @@ use test_utils::create_mint; /// 3. The vault has the correct owner and mint #[tokio::test] async fn test_create_token_vault() { - use light_token::instruction::{COMPRESSIBLE_CONFIG_V1, RENT_SPONSOR}; + use light_token::instruction::{LIGHT_TOKEN_CONFIG, LIGHT_TOKEN_RENT_SPONSOR}; use light_token_macro_create_token_account::{ CreateTokenVaultParams, VAULT_AUTH_SEED, VAULT_SEED, }; - use light_token_types::CPI_AUTHORITY_PDA; + use light_token::constants::LIGHT_TOKEN_CPI_AUTHORITY; let program_id = light_token_macro_create_token_account::ID; let config = ProgramTestConfig::new_v2( @@ -138,9 +138,9 @@ async fn test_create_token_vault() { mint, vault_authority, vault, - light_token_compressible_config: COMPRESSIBLE_CONFIG_V1, - light_token_rent_sponsor: RENT_SPONSOR, - light_token_cpi_authority: CPI_AUTHORITY_PDA.into(), + light_token_config: LIGHT_TOKEN_CONFIG, + light_token_rent_sponsor: LIGHT_TOKEN_RENT_SPONSOR, + light_token_cpi_authority: LIGHT_TOKEN_CPI_AUTHORITY, light_token_program: LIGHT_TOKEN_PROGRAM_ID, system_program: solana_sdk::system_program::ID, }; diff --git a/snippets/code-snippets/light-token/delegate-transfer/action.mdx b/snippets/code-snippets/light-token/delegate-transfer/action.mdx new file mode 100644 index 0000000..acb1760 --- /dev/null +++ b/snippets/code-snippets/light-token/delegate-transfer/action.mdx @@ -0,0 +1,65 @@ +```typescript +import "dotenv/config"; +import { Keypair } from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { + createMintInterface, + mintToCompressed, + getAssociatedTokenAddressInterface, +} from "@lightprotocol/compressed-token"; +import { + approveInterface, + transferDelegatedInterface, +} from "@lightprotocol/compressed-token/unified"; +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 () { + const { mint } = await createMintInterface(rpc, payer, payer, null, 9); + await mintToCompressed(rpc, payer, mint, payer, [ + { recipient: payer.publicKey, amount: 1000n }, + ]); + + const senderAta = getAssociatedTokenAddressInterface(mint, payer.publicKey); + const delegate = Keypair.generate(); + const recipient = Keypair.generate(); + + // Approve delegate + await approveInterface( + rpc, + payer, + senderAta, + mint, + delegate.publicKey, + 500_000, + payer + ); + console.log("Approved delegate:", delegate.publicKey.toBase58()); + + // Delegate transfers tokens on behalf of the owner + const tx = await transferDelegatedInterface( + rpc, + payer, + senderAta, + mint, + recipient.publicKey, + delegate, + payer.publicKey, + 200_000 + ); + + console.log("Delegated transfer:", tx); +})(); +``` diff --git a/snippets/code-snippets/light-token/extensions/close-mint/action.mdx b/snippets/code-snippets/light-token/extensions/close-mint/action.mdx new file mode 100644 index 0000000..194da71 --- /dev/null +++ b/snippets/code-snippets/light-token/extensions/close-mint/action.mdx @@ -0,0 +1,91 @@ +```typescript +import "dotenv/config"; +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + ExtensionType, + getMintLen, + createInitializeMint2Instruction, + createInitializeMintCloseAuthorityInstruction, +} from "@solana/spl-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 () { + const mintKeypair = Keypair.generate(); + const decimals = 9; + + // 1. Calculate space including the MintCloseAuthority extension + const mintLen = getMintLen([ExtensionType.MintCloseAuthority]); + const rentExemptBalance = await rpc.getMinimumBalanceForRentExemption( + mintLen + ); + + // 2. Create the mint account + const createMintAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, + }); + + // 3. Initialize the MintCloseAuthority extension + const initMintCloseAuthorityIx = + createInitializeMintCloseAuthorityInstruction( + mintKeypair.publicKey, + payer.publicKey, // close authority + TOKEN_2022_PROGRAM_ID + ); + + // 4. Initialize the mint + const initializeMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID + ); + + // 5. Register the SPL interface PDA with Light Token + const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); + + const tx = new Transaction().add( + createMintAccountIx, + initMintCloseAuthorityIx, + initializeMintIx, + createSplInterfaceIx + ); + + const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, + ]); + + console.log("Mint:", mintKeypair.publicKey.toBase58()); + console.log("Tx:", signature); +})(); +``` diff --git a/snippets/code-snippets/light-token/extensions/confidential-transfer/action.mdx b/snippets/code-snippets/light-token/extensions/confidential-transfer/action.mdx new file mode 100644 index 0000000..a0e1201 --- /dev/null +++ b/snippets/code-snippets/light-token/extensions/confidential-transfer/action.mdx @@ -0,0 +1,141 @@ +```typescript +import "dotenv/config"; +import { + Keypair, + PublicKey, + SystemProgram, + Transaction, + TransactionInstruction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + ExtensionType, + TOKEN_2022_PROGRAM_ID, + createInitializeMint2Instruction, + getMintLen, +} from "@solana/spl-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")) + ) +); + +/** + * Build the InitializeMint instruction for ConfidentialTransferMint. + * + * The @solana/spl-token SDK defines ExtensionType.ConfidentialTransferMint + * but does not yet export a helper for this instruction, so we construct + * it manually using the Token-2022 instruction layout. + */ +function createInitializeConfidentialTransferMintIx( + mint: PublicKey, + authority: PublicKey | null, + autoApproveNewAccounts: boolean, + auditorElGamalPubkey: Uint8Array | null, +): TransactionInstruction { + // TokenInstruction::ConfidentialTransferExtension = 27 + // ConfidentialTransferInstruction::InitializeMint = 0 + const data = Buffer.alloc(2 + 1 + 32 + 1 + 1 + 32); + let offset = 0; + data.writeUInt8(27, offset); offset += 1; // TokenInstruction + data.writeUInt8(0, offset); offset += 1; // InitializeMint sub-instruction + + // authority (COption): 1 byte tag + 32 bytes + if (authority) { + data.writeUInt8(1, offset); offset += 1; + authority.toBuffer().copy(data, offset); offset += 32; + } else { + data.writeUInt8(0, offset); offset += 1; + offset += 32; + } + + // auto_approve_new_accounts: bool (1 byte) + data.writeUInt8(autoApproveNewAccounts ? 1 : 0, offset); offset += 1; + + // auditor_elgamal_pubkey (COption): 1 byte tag + 32 bytes + if (auditorElGamalPubkey) { + data.writeUInt8(1, offset); offset += 1; + Buffer.from(auditorElGamalPubkey).copy(data, offset); + } else { + data.writeUInt8(0, offset); offset += 1; + } + + return new TransactionInstruction({ + keys: [{ pubkey: mint, isSigner: false, isWritable: true }], + programId: TOKEN_2022_PROGRAM_ID, + data, + }); +} + +(async function () { + const mintKeypair = Keypair.generate(); + const decimals = 9; + + // 1. Calculate space including ConfidentialTransferMint extension + const mintLen = getMintLen([ExtensionType.ConfidentialTransferMint]); + const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + + // 2. Create account + const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, + }); + + // 3. Initialize ConfidentialTransferMint extension (must come before mint init) + // auto_approve_new_accounts: false — extension is initialized but not enabled + // auditor_elgamal_pubkey: null — no auditor configured + const initConfidentialTransferIx = + createInitializeConfidentialTransferMintIx( + mintKeypair.publicKey, + payer.publicKey, // authority + false, // auto_approve_new_accounts (not enabled) + null, // auditor_elgamal_pubkey + ); + + // 4. Initialize mint + const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID, + ); + + // 5. Register interface PDA with Light Token + const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); + + const tx = new Transaction().add( + createAccountIx, + initConfidentialTransferIx, + initMintIx, + createSplInterfaceIx, + ); + + const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, + ]); + + console.log("Mint:", mintKeypair.publicKey.toBase58()); + console.log("Tx:", signature); +})(); +``` diff --git a/snippets/code-snippets/light-token/extensions/default-account-state/action.mdx b/snippets/code-snippets/light-token/extensions/default-account-state/action.mdx new file mode 100644 index 0000000..5092884 --- /dev/null +++ b/snippets/code-snippets/light-token/extensions/default-account-state/action.mdx @@ -0,0 +1,92 @@ +```typescript +import "dotenv/config"; +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + ExtensionType, + getMintLen, + createInitializeMint2Instruction, + createInitializeDefaultAccountStateInstruction, + AccountState, +} from "@solana/spl-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 () { + const mintKeypair = Keypair.generate(); + const decimals = 9; + + // 1. Calculate space including the DefaultAccountState extension + const mintLen = getMintLen([ExtensionType.DefaultAccountState]); + const rentExemptBalance = await rpc.getMinimumBalanceForRentExemption( + mintLen + ); + + // 2. Create the mint account + const createMintAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, + }); + + // 3. Initialize the DefaultAccountState extension (frozen by default) + const initDefaultAccountStateIx = + createInitializeDefaultAccountStateInstruction( + mintKeypair.publicKey, + AccountState.Frozen, + TOKEN_2022_PROGRAM_ID + ); + + // 4. Initialize the mint + const initializeMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + payer.publicKey, // freeze authority (required for frozen default state) + TOKEN_2022_PROGRAM_ID + ); + + // 5. Register the SPL interface PDA with Light Token + const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); + + const tx = new Transaction().add( + createMintAccountIx, + initDefaultAccountStateIx, + initializeMintIx, + createSplInterfaceIx + ); + + const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, + ]); + + console.log("Mint:", mintKeypair.publicKey.toBase58()); + console.log("Tx:", signature); +})(); +``` diff --git a/snippets/code-snippets/light-token/extensions/interest-bearing/action.mdx b/snippets/code-snippets/light-token/extensions/interest-bearing/action.mdx new file mode 100644 index 0000000..1a6043e --- /dev/null +++ b/snippets/code-snippets/light-token/extensions/interest-bearing/action.mdx @@ -0,0 +1,93 @@ +```typescript +import "dotenv/config"; +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + getMintLen, + createInitializeMint2Instruction, + ExtensionType, + createInitializeInterestBearingMintInstruction, +} from "@solana/spl-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 () { + const mintKeypair = Keypair.generate(); + const decimals = 9; + const rate = 500; // 5% interest rate in basis points + + // Calculate space for mint + InterestBearingConfig extension + const mintLen = getMintLen([ExtensionType.InterestBearingConfig]); + const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + + // Instruction 1: Create account + const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, + }); + + // Instruction 2: Initialize InterestBearingConfig + const initInterestBearingIx = + createInitializeInterestBearingMintInstruction( + mintKeypair.publicKey, + payer.publicKey, // rate authority + rate, + TOKEN_2022_PROGRAM_ID + ); + + // Instruction 3: Initialize mint + const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID + ); + + // Instruction 4: Create SPL interface PDA + // Holds Token-2022 tokens when wrapped to light-token + const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); + + const tx = new Transaction().add( + createAccountIx, + initInterestBearingIx, + initMintIx, + createSplInterfaceIx + ); + + const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, + ]); + + console.log("Mint:", mintKeypair.publicKey.toBase58()); + console.log("Tx:", signature); +})(); +``` diff --git a/snippets/code-snippets/light-token/extensions/metadata-pointer/action.mdx b/snippets/code-snippets/light-token/extensions/metadata-pointer/action.mdx new file mode 100644 index 0000000..6694b00 --- /dev/null +++ b/snippets/code-snippets/light-token/extensions/metadata-pointer/action.mdx @@ -0,0 +1,120 @@ +```typescript +import "dotenv/config"; +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + getMintLen, + createInitializeMint2Instruction, + ExtensionType, + createInitializeMetadataPointerInstruction, +} from "@solana/spl-token"; +import { + createInitializeInstruction as createInitializeTokenMetadataInstruction, + pack, + TokenMetadata, +} from "@solana/spl-token-metadata"; +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 () { + const mintKeypair = Keypair.generate(); + const decimals = 9; + + const metadata: TokenMetadata = { + mint: mintKeypair.publicKey, + name: "Example Token", + symbol: "EXT", + uri: "https://example.com/metadata.json", + additionalMetadata: [], + }; + + // Calculate space for mint + MetadataPointer extension + const mintLen = getMintLen([ExtensionType.MetadataPointer]); + const metadataLen = pack(metadata).length; + const totalLen = mintLen + metadataLen; + const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(totalLen); + + // Instruction 1: Create account + const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, + }); + + // Instruction 2: Initialize MetadataPointer (points to the mint itself) + const initMetadataPointerIx = + createInitializeMetadataPointerInstruction( + mintKeypair.publicKey, + payer.publicKey, + mintKeypair.publicKey, // metadata address = mint itself + TOKEN_2022_PROGRAM_ID + ); + + // Instruction 3: Initialize mint + const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID + ); + + // Instruction 4: Initialize TokenMetadata on the mint + const initTokenMetadataIx = createInitializeTokenMetadataInstruction({ + programId: TOKEN_2022_PROGRAM_ID, + mint: mintKeypair.publicKey, + metadata: mintKeypair.publicKey, + mintAuthority: payer.publicKey, + name: metadata.name, + symbol: metadata.symbol, + uri: metadata.uri, + updateAuthority: payer.publicKey, + }); + + // Instruction 5: Create SPL interface PDA + // Holds Token-2022 tokens when wrapped to light-token + const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); + + const tx = new Transaction().add( + createAccountIx, + initMetadataPointerIx, + initMintIx, + initTokenMetadataIx, + createSplInterfaceIx + ); + + const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, + ]); + + console.log("Mint:", mintKeypair.publicKey.toBase58()); + console.log("Tx:", signature); +})(); +``` diff --git a/snippets/code-snippets/light-token/extensions/pausable/action.mdx b/snippets/code-snippets/light-token/extensions/pausable/action.mdx new file mode 100644 index 0000000..4208424 --- /dev/null +++ b/snippets/code-snippets/light-token/extensions/pausable/action.mdx @@ -0,0 +1,89 @@ +```typescript +import "dotenv/config"; +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + ExtensionType, + TOKEN_2022_PROGRAM_ID, + createInitializeMint2Instruction, + createInitializePausableConfigInstruction, + getMintLen, +} from "@solana/spl-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 () { + const mintKeypair = Keypair.generate(); + const decimals = 9; + + // 1. Calculate space including the Pausable extension + const mintLen = getMintLen([ExtensionType.PausableConfig]); + const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + + // 2. Create account + const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, + }); + + // 3. Initialize Pausable extension (must come before mint init) + const initPausableIx = createInitializePausableConfigInstruction( + mintKeypair.publicKey, + payer.publicKey, // pause authority + TOKEN_2022_PROGRAM_ID, + ); + + // 4. Initialize mint + const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID, + ); + + // 5. Register interface PDA with Light Token + const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); + + const tx = new Transaction().add( + createAccountIx, + initPausableIx, + initMintIx, + createSplInterfaceIx, + ); + + const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, + ]); + + console.log("Mint:", mintKeypair.publicKey.toBase58()); + console.log("Tx:", signature); +})(); +``` diff --git a/snippets/code-snippets/light-token/extensions/permanent-delegate/action.mdx b/snippets/code-snippets/light-token/extensions/permanent-delegate/action.mdx new file mode 100644 index 0000000..9d8376b --- /dev/null +++ b/snippets/code-snippets/light-token/extensions/permanent-delegate/action.mdx @@ -0,0 +1,91 @@ +```typescript +import "dotenv/config"; +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + ExtensionType, + getMintLen, + createInitializeMint2Instruction, + createInitializePermanentDelegateInstruction, +} from "@solana/spl-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 () { + const mintKeypair = Keypair.generate(); + const decimals = 9; + + // 1. Calculate space including the PermanentDelegate extension + const mintLen = getMintLen([ExtensionType.PermanentDelegate]); + const rentExemptBalance = await rpc.getMinimumBalanceForRentExemption( + mintLen + ); + + // 2. Create the mint account + const createMintAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, + }); + + // 3. Initialize the PermanentDelegate extension + const initPermanentDelegateIx = + createInitializePermanentDelegateInstruction( + mintKeypair.publicKey, + payer.publicKey, // permanent delegate authority + TOKEN_2022_PROGRAM_ID + ); + + // 4. Initialize the mint + const initializeMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID + ); + + // 5. Register the SPL interface PDA with Light Token + const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); + + const tx = new Transaction().add( + createMintAccountIx, + initPermanentDelegateIx, + initializeMintIx, + createSplInterfaceIx + ); + + const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, + ]); + + console.log("Mint:", mintKeypair.publicKey.toBase58()); + console.log("Tx:", signature); +})(); +``` diff --git a/snippets/code-snippets/light-token/extensions/token-groups/action.mdx b/snippets/code-snippets/light-token/extensions/token-groups/action.mdx new file mode 100644 index 0000000..5aeebc5 --- /dev/null +++ b/snippets/code-snippets/light-token/extensions/token-groups/action.mdx @@ -0,0 +1,179 @@ +```typescript +import "dotenv/config"; +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + ExtensionType, + getMintLen, + createInitializeMint2Instruction, + createInitializeGroupPointerInstruction, + createInitializeGroupInstruction, + createInitializeGroupMemberPointerInstruction, + createInitializeMemberInstruction, +} from "@solana/spl-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 () { + // ===== Step 1: Create a group mint ===== + const groupMintKeypair = Keypair.generate(); + const decimals = 0; + + // Calculate space including GroupPointer and TokenGroup extensions + const groupMintLen = getMintLen([ + ExtensionType.GroupPointer, + ExtensionType.TokenGroup, + ]); + const groupRentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(groupMintLen); + + // Create the group mint account + const createGroupMintIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: groupRentExemptBalance, + newAccountPubkey: groupMintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: groupMintLen, + }); + + // Initialize GroupPointer (points to the mint itself) + const initGroupPointerIx = createInitializeGroupPointerInstruction( + groupMintKeypair.publicKey, + payer.publicKey, // authority + groupMintKeypair.publicKey, // group address (self-referencing) + TOKEN_2022_PROGRAM_ID + ); + + // Initialize the group mint + const initGroupMintIx = createInitializeMint2Instruction( + groupMintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID + ); + + // Initialize the TokenGroup data on the mint + const initGroupIx = createInitializeGroupInstruction({ + group: groupMintKeypair.publicKey, + maxSize: 100, + mint: groupMintKeypair.publicKey, + mintAuthority: payer.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + updateAuthority: payer.publicKey, + }); + + // Register the group mint with Light Token + const registerGroupIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: groupMintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); + + const groupTx = new Transaction().add( + createGroupMintIx, + initGroupPointerIx, + initGroupMintIx, + initGroupIx, + registerGroupIx + ); + + const groupSignature = await sendAndConfirmTransaction(rpc, groupTx, [ + payer, + groupMintKeypair, + ]); + + console.log("Group Mint:", groupMintKeypair.publicKey.toBase58()); + console.log("Group Tx:", groupSignature); + + // ===== Step 2: Create a member mint ===== + const memberMintKeypair = Keypair.generate(); + + // Calculate space including GroupMemberPointer and TokenGroupMember extensions + const memberMintLen = getMintLen([ + ExtensionType.GroupMemberPointer, + ExtensionType.TokenGroupMember, + ]); + const memberRentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(memberMintLen); + + // Create the member mint account + const createMemberMintIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: memberRentExemptBalance, + newAccountPubkey: memberMintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: memberMintLen, + }); + + // Initialize GroupMemberPointer (points to the member mint itself) + const initMemberPointerIx = + createInitializeGroupMemberPointerInstruction( + memberMintKeypair.publicKey, + payer.publicKey, // authority + memberMintKeypair.publicKey, // member address (self-referencing) + TOKEN_2022_PROGRAM_ID + ); + + // Initialize the member mint + const initMemberMintIx = createInitializeMint2Instruction( + memberMintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID + ); + + // Initialize the TokenGroupMember data on the member mint + const initMemberIx = createInitializeMemberInstruction({ + group: groupMintKeypair.publicKey, + groupUpdateAuthority: payer.publicKey, + member: memberMintKeypair.publicKey, + memberMint: memberMintKeypair.publicKey, + memberMintAuthority: payer.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + }); + + // Register the member mint with Light Token + const registerMemberIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: memberMintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); + + const memberTx = new Transaction().add( + createMemberMintIx, + initMemberPointerIx, + initMemberMintIx, + initMemberIx, + registerMemberIx + ); + + const memberSignature = await sendAndConfirmTransaction(rpc, memberTx, [ + payer, + memberMintKeypair, + ]); + + console.log("Member Mint:", memberMintKeypair.publicKey.toBase58()); + console.log("Member Tx:", memberSignature); +})(); +``` diff --git a/snippets/code-snippets/light-token/extensions/transfer-fees/action.mdx b/snippets/code-snippets/light-token/extensions/transfer-fees/action.mdx new file mode 100644 index 0000000..82cf3f6 --- /dev/null +++ b/snippets/code-snippets/light-token/extensions/transfer-fees/action.mdx @@ -0,0 +1,94 @@ +```typescript +import "dotenv/config"; +import { + Keypair, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + getMintLen, + createInitializeMint2Instruction, + ExtensionType, + createInitializeTransferFeeConfigInstruction, +} from "@solana/spl-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 () { + const mintKeypair = Keypair.generate(); + const decimals = 9; + + // Calculate space for mint + TransferFeeConfig extension + const mintLen = getMintLen([ExtensionType.TransferFeeConfig]); + const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + + // Instruction 1: Create account + const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, + }); + + // Instruction 2: Initialize TransferFeeConfig with zero fees + // Light Token requires fees to be zero + const initTransferFeeIx = createInitializeTransferFeeConfigInstruction( + mintKeypair.publicKey, + payer.publicKey, // transfer fee config authority + payer.publicKey, // withdraw withheld authority + 0, // fee basis points (must be zero) + BigInt(0), // maximum fee (must be zero) + TOKEN_2022_PROGRAM_ID + ); + + // Instruction 3: Initialize mint + const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID + ); + + // Instruction 4: Create SPL interface PDA + // Holds Token-2022 tokens when wrapped to light-token + const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); + + const tx = new Transaction().add( + createAccountIx, + initTransferFeeIx, + initMintIx, + createSplInterfaceIx + ); + + const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, + ]); + + console.log("Mint:", mintKeypair.publicKey.toBase58()); + console.log("Tx:", signature); +})(); +``` diff --git a/snippets/code-snippets/light-token/extensions/transfer-hook/action.mdx b/snippets/code-snippets/light-token/extensions/transfer-hook/action.mdx new file mode 100644 index 0000000..4e6237d --- /dev/null +++ b/snippets/code-snippets/light-token/extensions/transfer-hook/action.mdx @@ -0,0 +1,93 @@ +```typescript +import "dotenv/config"; +import { + Keypair, + PublicKey, + SystemProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { + TOKEN_2022_PROGRAM_ID, + getMintLen, + createInitializeMint2Instruction, + ExtensionType, + createInitializeTransferHookInstruction, +} from "@solana/spl-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 () { + const mintKeypair = Keypair.generate(); + const decimals = 9; + + // Calculate space for mint + TransferHook extension + const mintLen = getMintLen([ExtensionType.TransferHook]); + const rentExemptBalance = + await rpc.getMinimumBalanceForRentExemption(mintLen); + + // Instruction 1: Create account + const createAccountIx = SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + lamports: rentExemptBalance, + newAccountPubkey: mintKeypair.publicKey, + programId: TOKEN_2022_PROGRAM_ID, + space: mintLen, + }); + + // Instruction 2: Initialize TransferHook with nil program_id (hook disabled) + // Light Token requires program_id to be nil (PublicKey.default) + const initTransferHookIx = createInitializeTransferHookInstruction( + mintKeypair.publicKey, + payer.publicKey, // authority + PublicKey.default, // program_id must be nil + TOKEN_2022_PROGRAM_ID + ); + + // Instruction 3: Initialize mint + const initMintIx = createInitializeMint2Instruction( + mintKeypair.publicKey, + decimals, + payer.publicKey, // mint authority + null, // freeze authority + TOKEN_2022_PROGRAM_ID + ); + + // Instruction 4: Create SPL interface PDA + // Holds Token-2022 tokens when wrapped to light-token + const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); + + const tx = new Transaction().add( + createAccountIx, + initTransferHookIx, + initMintIx, + createSplInterfaceIx + ); + + const signature = await sendAndConfirmTransaction(rpc, tx, [ + payer, + mintKeypair, + ]); + + console.log("Mint:", mintKeypair.publicKey.toBase58()); + console.log("Tx:", signature); +})(); +``` diff --git a/snippets/code-snippets/light-token/load-ata/action.mdx b/snippets/code-snippets/light-token/load-ata/action.mdx index 919ef14..8f80849 100644 --- a/snippets/code-snippets/light-token/load-ata/action.mdx +++ b/snippets/code-snippets/light-token/load-ata/action.mdx @@ -7,15 +7,15 @@ import { mintToCompressed, loadAta, getAssociatedTokenAddressInterface, -} from "@lightprotocol/compressed-token/unified"; +} 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); +// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +// const rpc = createRpc(RPC_URL); // localnet: -// const rpc = createRpc(); +const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( @@ -24,14 +24,19 @@ const payer = Keypair.fromSecretKey( ); (async function () { - // Setup: Get compressed tokens (cold storage) + // 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 }, ]); - // Load compressed tokens to hot balance - const lightTokenAta = getAssociatedTokenAddressInterface(mint, payer.publicKey); + // Load compressed tokens to light associated token account (hot balance) + const lightTokenAta = getAssociatedTokenAddressInterface( + mint, + payer.publicKey + ); const tx = await loadAta(rpc, lightTokenAta, payer, mint, payer); console.log("Tx:", tx); diff --git a/snippets/code-snippets/light-token/load-ata/instruction.mdx b/snippets/code-snippets/light-token/load-ata/instruction.mdx index 7d10f34..cb5b9ea 100644 --- a/snippets/code-snippets/light-token/load-ata/instruction.mdx +++ b/snippets/code-snippets/light-token/load-ata/instruction.mdx @@ -11,7 +11,7 @@ import { mintToCompressed, createLoadAtaInstructions, getAssociatedTokenAddressInterface, -} from "@lightprotocol/compressed-token/unified"; +} from "@lightprotocol/compressed-token"; import { homedir } from "os"; import { readFileSync } from "fs"; @@ -23,8 +23,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -32,29 +32,29 @@ const payer = Keypair.fromSecretKey( // 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 }]); + await mintToCompressed(rpc, payer, mint, payer, [ + { recipient: payer.publicKey, amount: 1000n }, + ]); const lightTokenAta = getAssociatedTokenAddressInterface( mint, - payer.publicKey, + payer.publicKey ); - // Load compressed tokens to light associated token account (hot balance). Usually one tx. Empty = noop. - const instructions = await createLoadAtaInstructions( + // Load compressed tokens to light associated token account (hot balance) + const ixs = await createLoadAtaInstructions( rpc, lightTokenAta, payer.publicKey, mint, - payer.publicKey, + payer.publicKey ); - if (instructions.length === 0) return console.log("Nothing to load"); + if (ixs.length === 0) return console.log("Nothing to load"); - for (const ixs of instructions) { - const { blockhash } = await rpc.getLatestBlockhash(); - const tx = buildAndSignTx(ixs, payer, blockhash); - const sig = await sendAndConfirmTx(rpc, tx); - console.log("Tx:", sig); - } + const blockhash = await rpc.getLatestBlockhash(); + const tx = buildAndSignTx(ixs, payer, blockhash.blockhash); + const signature = await sendAndConfirmTx(rpc, tx); + console.log("Tx:", signature); })(); ``` diff --git a/snippets/code-snippets/light-token/mint-to/action.mdx b/snippets/code-snippets/light-token/mint-to/action.mdx index 9aa231b..ec43e0f 100644 --- a/snippets/code-snippets/light-token/mint-to/action.mdx +++ b/snippets/code-snippets/light-token/mint-to/action.mdx @@ -12,10 +12,10 @@ 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); +// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +// const rpc = createRpc(RPC_URL); // localnet: -// const rpc = createRpc(); +const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( @@ -29,8 +29,18 @@ const payer = Keypair.fromSecretKey( const recipient = Keypair.generate(); await createAtaInterface(rpc, payer, mint, recipient.publicKey); - const destination = getAssociatedTokenAddressInterface(mint, recipient.publicKey); - const tx = await mintToInterface(rpc, payer, mint, destination, payer, 1_000_000_000); + const destination = getAssociatedTokenAddressInterface( + mint, + recipient.publicKey + ); + const tx = await mintToInterface( + rpc, + payer, + mint, + destination, + payer, + 1_000_000_000 + ); console.log("Tx:", tx); })(); diff --git a/snippets/code-snippets/light-token/mint-to/anchor-program/full-example.mdx b/snippets/code-snippets/light-token/mint-to/anchor-program/full-example.mdx index 79393ab..82f6509 100644 --- a/snippets/code-snippets/light-token/mint-to/anchor-program/full-example.mdx +++ b/snippets/code-snippets/light-token/mint-to/anchor-program/full-example.mdx @@ -18,8 +18,7 @@ pub mod light_token_anchor_mint_to { amount, authority: ctx.accounts.authority.to_account_info(), system_program: ctx.accounts.system_program.to_account_info(), - max_top_up: None, - fee_payer: None, + fee_payer: ctx.accounts.fee_payer.to_account_info(), } .invoke()?; Ok(()) @@ -37,6 +36,8 @@ pub struct MintToAccounts<'info> { #[account(mut)] pub destination: AccountInfo<'info>, pub authority: Signer<'info>, + #[account(mut)] + pub fee_payer: Signer<'info>, pub system_program: Program<'info, System>, } ``` @@ -63,6 +64,7 @@ async fn test_mint_to() { mint: env.mint_pda, destination: env.associated_token_account, authority: env.payer.pubkey(), + fee_payer: env.payer.pubkey(), system_program: system_program::ID, } .to_account_metas(Some(true)), diff --git a/snippets/code-snippets/light-token/mint-to/instruction.mdx b/snippets/code-snippets/light-token/mint-to/instruction.mdx index fcaf80d..7a2ccc6 100644 --- a/snippets/code-snippets/light-token/mint-to/instruction.mdx +++ b/snippets/code-snippets/light-token/mint-to/instruction.mdx @@ -25,8 +25,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -36,7 +36,7 @@ const payer = Keypair.fromSecretKey( await createAtaInterface(rpc, payer, mint, recipient.publicKey); const destination = getAssociatedTokenAddressInterface( mint, - recipient.publicKey, + recipient.publicKey ); const mintInterface = await getMintInterface(rpc, mint); @@ -53,7 +53,7 @@ const payer = Keypair.fromSecretKey( }, ], [], - DerivationMode.compressible, + DerivationMode.compressible ); } @@ -63,12 +63,12 @@ const payer = Keypair.fromSecretKey( payer.publicKey, payer.publicKey, 1_000_000_000, - validityProof, + validityProof ); const tx = new Transaction().add( ComputeBudgetProgram.setComputeUnitLimit({ units: 500_000 }), - ix, + ix ); const signature = await sendAndConfirmTransaction(rpc, tx, [payer]); diff --git a/snippets/code-snippets/light-token/revoke/anchor-program/full-example.mdx b/snippets/code-snippets/light-token/revoke/anchor-program/full-example.mdx index ff84e80..5464969 100644 --- a/snippets/code-snippets/light-token/revoke/anchor-program/full-example.mdx +++ b/snippets/code-snippets/light-token/revoke/anchor-program/full-example.mdx @@ -16,6 +16,7 @@ pub mod light_token_anchor_revoke { token_account: ctx.accounts.token_account.to_account_info(), owner: ctx.accounts.owner.to_account_info(), system_program: ctx.accounts.system_program.to_account_info(), + fee_payer: ctx.accounts.fee_payer.to_account_info(), } .invoke()?; Ok(()) @@ -30,6 +31,8 @@ pub struct RevokeAccounts<'info> { #[account(mut)] pub token_account: AccountInfo<'info>, pub owner: Signer<'info>, + #[account(mut)] + pub fee_payer: Signer<'info>, pub system_program: Program<'info, System>, } ``` @@ -58,6 +61,7 @@ async fn test_revoke() { delegate: delegate.pubkey(), owner: env.payer.pubkey(), amount: 500_000, + fee_payer: env.payer.pubkey(), } .instruction() .unwrap(); @@ -74,6 +78,7 @@ async fn test_revoke() { light_token_program: LIGHT_TOKEN_PROGRAM_ID, token_account: env.associated_token_account, owner: env.payer.pubkey(), + fee_payer: env.payer.pubkey(), system_program: system_program::ID, } .to_account_metas(Some(true)), diff --git a/snippets/code-snippets/light-token/transfer-checked/anchor-program/full-example.mdx b/snippets/code-snippets/light-token/transfer-checked/anchor-program/full-example.mdx index cd870a7..d933e07 100644 --- a/snippets/code-snippets/light-token/transfer-checked/anchor-program/full-example.mdx +++ b/snippets/code-snippets/light-token/transfer-checked/anchor-program/full-example.mdx @@ -24,8 +24,7 @@ pub mod light_token_anchor_transfer_checked { decimals, authority: ctx.accounts.authority.to_account_info(), system_program: ctx.accounts.system_program.to_account_info(), - max_top_up: None, - fee_payer: None, + fee_payer: ctx.accounts.fee_payer.to_account_info(), } .invoke()?; Ok(()) @@ -45,6 +44,8 @@ pub struct TransferCheckedAccounts<'info> { #[account(mut)] pub destination: AccountInfo<'info>, pub authority: Signer<'info>, + #[account(mut)] + pub fee_payer: Signer<'info>, pub system_program: Program<'info, System>, } ``` @@ -82,6 +83,7 @@ async fn test_transfer_checked() { mint: env.mint_pda, destination: dest_associated_token_account, authority: env.payer.pubkey(), + fee_payer: env.payer.pubkey(), system_program: system_program::ID, } .to_account_metas(Some(true)), diff --git a/snippets/code-snippets/light-token/transfer-interface/action.mdx b/snippets/code-snippets/light-token/transfer-interface/action.mdx index 46e3357..a8bb21d 100644 --- a/snippets/code-snippets/light-token/transfer-interface/action.mdx +++ b/snippets/code-snippets/light-token/transfer-interface/action.mdx @@ -13,10 +13,10 @@ 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); +// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +// const rpc = createRpc(RPC_URL); // localnet: -// const rpc = createRpc(); +const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( @@ -29,13 +29,30 @@ const payer = Keypair.fromSecretKey( const sender = Keypair.generate(); await createAtaInterface(rpc, payer, mint, sender.publicKey); - const senderAta = getAssociatedTokenAddressInterface(mint, sender.publicKey); + const senderAta = getAssociatedTokenAddressInterface( + mint, + sender.publicKey + ); await mintToInterface(rpc, payer, mint, senderAta, payer, 1_000_000_000); const recipient = Keypair.generate(); + await createAtaInterface(rpc, payer, mint, recipient.publicKey); + const recipientAta = getAssociatedTokenAddressInterface( + mint, + recipient.publicKey + ); - // destination is a wallet pubkey; the action creates the recipient ATA. - const tx = await transferInterface(rpc, payer, senderAta, mint, recipient.publicKey, sender, 500_000_000); + // Transfer tokens between light-token associated token accounts + // destination is recipient wallet; transferInterface creates recipient ATA idempotently + const tx = await transferInterface( + rpc, + payer, + senderAta, + mint, + recipient.publicKey, + sender, + 500_000_000 + ); console.log("Tx:", tx); })(); diff --git a/snippets/code-snippets/light-token/transfer-interface/anchor-program/full-example.mdx b/snippets/code-snippets/light-token/transfer-interface/anchor-program/full-example.mdx index 1f9ba0f..a315ed2 100644 --- a/snippets/code-snippets/light-token/transfer-interface/anchor-program/full-example.mdx +++ b/snippets/code-snippets/light-token/transfer-interface/anchor-program/full-example.mdx @@ -25,13 +25,14 @@ pub mod light_token_anchor_transfer_interface { ctx.accounts.authority.to_account_info(), ctx.accounts.payer.to_account_info(), ctx.accounts.cpi_authority.to_account_info(), + ctx.accounts.mint.to_account_info(), ctx.accounts.system_program.to_account_info(), ); if let Some(bump) = spl_interface_pda_bump { transfer = transfer .with_spl_interface( - ctx.accounts.mint.as_ref().map(|a| a.to_account_info()), + Some(ctx.accounts.mint.to_account_info()), ctx.accounts .spl_token_program .as_ref() @@ -42,10 +43,10 @@ pub mod light_token_anchor_transfer_interface { .map(|a| a.to_account_info()), Some(bump), ) - .map_err(|e| ProgramError::from(e))?; + ?; } - transfer.invoke().map_err(|e| ProgramError::from(e))?; + transfer.invoke()?; Ok(()) } } @@ -67,9 +68,9 @@ pub struct TransferAccounts<'info> { pub cpi_authority: AccountInfo<'info>, pub system_program: Program<'info, System>, - // SPL interface accounts (optional, for cross-type transfers) /// CHECK: Validated by light-token CPI - token mint - pub mint: Option>, + pub mint: AccountInfo<'info>, + // SPL interface accounts (optional, for cross-type transfers) /// CHECK: SPL Token or Token-2022 program pub spl_token_program: Option>, /// CHECK: Validated by light-token CPI - pool PDA @@ -123,7 +124,7 @@ async fn test_transfer() { payer: env.payer.pubkey(), cpi_authority: cpi_authority_pda, system_program: system_program::ID, - mint: None, + mint: env.mint_pda, spl_token_program: None, spl_interface_pda: None, } @@ -189,7 +190,7 @@ async fn test_transfer_spl_to_light() { .await .unwrap(); - // 2. Create SPL Interface PDA + // 2. Create SPL token pool (spl_interface_pda) let create_pool_ix = CreateSplInterfacePda::new(payer.pubkey(), mint, spl_token::ID, false).instruction(); @@ -246,7 +247,7 @@ async fn test_transfer_spl_to_light() { // 4. Create Light ATA for destination let recipient = Keypair::new(); - let (dest_ata, _) = derive_token_ata(&recipient.pubkey(), &mint); + let dest_ata = derive_token_ata(&recipient.pubkey(), &mint); let create_ata_ix = CreateAssociatedTokenAccount::new(payer.pubkey(), recipient.pubkey(), mint) .instruction() .unwrap(); @@ -271,7 +272,7 @@ async fn test_transfer_spl_to_light() { payer: payer.pubkey(), cpi_authority: cpi_authority_pda, system_program: system_program::ID, - mint: Some(mint), + mint: mint, spl_token_program: Some(spl_token::ID), spl_interface_pda: Some(spl_interface_pda), } diff --git a/snippets/code-snippets/light-token/transfer-interface/instruction.mdx b/snippets/code-snippets/light-token/transfer-interface/instruction.mdx index 8fd0892..5e94b69 100644 --- a/snippets/code-snippets/light-token/transfer-interface/instruction.mdx +++ b/snippets/code-snippets/light-token/transfer-interface/instruction.mdx @@ -2,7 +2,6 @@ import "dotenv/config"; import { Keypair, - ComputeBudgetProgram, Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; @@ -25,8 +24,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -36,7 +35,7 @@ const payer = Keypair.fromSecretKey( await createAtaInterface(rpc, payer, mint, sender.publicKey); const senderAta = getAssociatedTokenAddressInterface( mint, - sender.publicKey, + sender.publicKey ); await mintToInterface(rpc, payer, mint, senderAta, payer, 1_000_000_000); @@ -44,7 +43,7 @@ const payer = Keypair.fromSecretKey( await createAtaInterface(rpc, payer, mint, recipient.publicKey); const recipientAta = getAssociatedTokenAddressInterface( mint, - recipient.publicKey, + recipient.publicKey ); // Transfer tokens. Optional feePayer lets an application cover top-ups @@ -54,7 +53,7 @@ const payer = Keypair.fromSecretKey( recipientAta, sender.publicKey, // owner (signs the transfer) 500_000_000, - payer.publicKey, // optional: separate feePayer covers top-up + payer.publicKey // optional: separate feePayer covers top-up ); const tx = new Transaction().add(ix); diff --git a/snippets/code-snippets/light-token/unwrap/action.mdx b/snippets/code-snippets/light-token/unwrap/action.mdx index cdd5d61..1afdef1 100644 --- a/snippets/code-snippets/light-token/unwrap/action.mdx +++ b/snippets/code-snippets/light-token/unwrap/action.mdx @@ -1,18 +1,26 @@ ```typescript import "dotenv/config"; import { Keypair } from "@solana/web3.js"; -import { createRpc, bn } from "@lightprotocol/stateless.js"; -import { createMint, mintTo } from "@lightprotocol/compressed-token"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { + createMintInterface, + createAtaInterface, + mintToInterface, + getAssociatedTokenAddressInterface, +} from "@lightprotocol/compressed-token"; import { unwrap } from "@lightprotocol/compressed-token/unified"; -import { createAssociatedTokenAccount } from "@solana/spl-token"; +import { + createAssociatedTokenAccount, + TOKEN_2022_PROGRAM_ID, +} from "@solana/spl-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); +// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +// const rpc = createRpc(RPC_URL); // localnet: -// const rpc = createRpc(); +const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( @@ -21,18 +29,25 @@ const payer = Keypair.fromSecretKey( ); (async function () { - // Setup: Get compressed tokens (cold storage) - const { mint } = await createMint(rpc, payer, payer.publicKey, 9); - await mintTo(rpc, payer, mint, payer.publicKey, payer, bn(1000)); + // Setup: Create and mint tokens to light-token associated token account + const { mint } = await createMintInterface(rpc, payer, payer, null, 9); + await createAtaInterface(rpc, payer, mint, payer.publicKey); + const destination = getAssociatedTokenAddressInterface( + mint, + payer.publicKey + ); + await mintToInterface(rpc, payer, mint, destination, payer, 1000); - // Unwrap rent-free tokens to SPL ATA + // Unwrap light-token to SPL associated token account const splAta = await createAssociatedTokenAccount( rpc, payer, mint, - payer.publicKey + payer.publicKey, + undefined, + TOKEN_2022_PROGRAM_ID ); - const tx = await unwrap(rpc, payer, splAta, payer, mint, bn(500)); + const tx = await unwrap(rpc, payer, splAta, payer, mint, 500); console.log("Tx:", tx); })(); diff --git a/snippets/code-snippets/light-token/unwrap/instruction.mdx b/snippets/code-snippets/light-token/unwrap/instruction.mdx index 5f38a5b..bd9ca20 100644 --- a/snippets/code-snippets/light-token/unwrap/instruction.mdx +++ b/snippets/code-snippets/light-token/unwrap/instruction.mdx @@ -5,20 +5,27 @@ import { Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; -import { createRpc, bn } from "@lightprotocol/stateless.js"; +import { createRpc } from "@lightprotocol/stateless.js"; import { createMintInterface, - mintToCompressed, + createAtaInterface, + mintToInterface, + getAssociatedTokenAddressInterface, createUnwrapInstructions, } from "@lightprotocol/compressed-token/unified"; -import { createAssociatedTokenAccount } from "@solana/spl-token"; +import { + createAssociatedTokenAccount, + TOKEN_2022_PROGRAM_ID, +} from "@solana/spl-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 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")) @@ -26,16 +33,23 @@ const payer = Keypair.fromSecretKey( ); (async function () { + // Setup: Create and mint tokens to 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 }, - ]); + await createAtaInterface(rpc, payer, mint, payer.publicKey); + const destination = getAssociatedTokenAddressInterface( + mint, + payer.publicKey + ); + await mintToInterface(rpc, payer, mint, destination, payer, 1000); + // Create destination SPL ATA const splAta = await createAssociatedTokenAccount( rpc, payer, mint, - payer.publicKey + payer.publicKey, + undefined, + TOKEN_2022_PROGRAM_ID ); // Returns TransactionInstruction[][]. Each inner array is one txn. @@ -45,13 +59,14 @@ const payer = Keypair.fromSecretKey( splAta, payer.publicKey, mint, - 500n, + 500, payer.publicKey ); for (const ixs of instructions) { const tx = new Transaction().add(...ixs); - await sendAndConfirmTransaction(rpc, tx, [payer]); + const signature = await sendAndConfirmTransaction(rpc, tx, [payer]); + console.log("Tx:", signature); } })(); ``` diff --git a/snippets/code-snippets/light-token/wrap/action.mdx b/snippets/code-snippets/light-token/wrap/action.mdx index d81baaf..18b646a 100644 --- a/snippets/code-snippets/light-token/wrap/action.mdx +++ b/snippets/code-snippets/light-token/wrap/action.mdx @@ -1,24 +1,28 @@ ```typescript import "dotenv/config"; import { Keypair } from "@solana/web3.js"; -import { createRpc, bn } from "@lightprotocol/stateless.js"; +import { createRpc } from "@lightprotocol/stateless.js"; import { - createMint, - mintTo, - decompress, + createMintInterface, + createAtaInterface, + mintToInterface, + decompressInterface, wrap, getAssociatedTokenAddressInterface, createAtaInterfaceIdempotent, } from "@lightprotocol/compressed-token"; -import { createAssociatedTokenAccount } from "@solana/spl-token"; +import { + createAssociatedTokenAccount, + TOKEN_2022_PROGRAM_ID, +} from "@solana/spl-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); +// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +// const rpc = createRpc(RPC_URL); // localnet: -// const rpc = createRpc(); +const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( @@ -28,21 +32,31 @@ const payer = Keypair.fromSecretKey( (async function () { // Setup: Get SPL tokens (needed to wrap) - const { mint } = await createMint(rpc, payer, payer.publicKey, 9); + const { mint } = await createMintInterface(rpc, payer, payer, null, 9); + await createAtaInterface(rpc, payer, mint, payer.publicKey); + const destination = getAssociatedTokenAddressInterface( + mint, + payer.publicKey + ); + await mintToInterface(rpc, payer, mint, destination, payer, 1000); const splAta = await createAssociatedTokenAccount( rpc, payer, mint, - payer.publicKey + payer.publicKey, + undefined, + TOKEN_2022_PROGRAM_ID ); - await mintTo(rpc, payer, mint, payer.publicKey, payer, bn(1000)); - await decompress(rpc, payer, mint, bn(1000), payer, splAta); + await decompressInterface(rpc, payer, payer, mint, 1000); - // Wrap SPL tokens to rent-free token ATA - const lightTokenAta = getAssociatedTokenAddressInterface(mint, payer.publicKey); + // Wrap SPL tokens to light-token associated token account + const lightTokenAta = getAssociatedTokenAddressInterface( + mint, + payer.publicKey + ); await createAtaInterfaceIdempotent(rpc, payer, mint, payer.publicKey); - const tx = await wrap(rpc, payer, splAta, lightTokenAta, payer, mint, bn(500)); + const tx = await wrap(rpc, payer, splAta, lightTokenAta, payer, mint, 500); console.log("Tx:", tx); })(); diff --git a/snippets/code-snippets/light-token/wrap/instruction.mdx b/snippets/code-snippets/light-token/wrap/instruction.mdx index e360f5d..3b34766 100644 --- a/snippets/code-snippets/light-token/wrap/instruction.mdx +++ b/snippets/code-snippets/light-token/wrap/instruction.mdx @@ -1,25 +1,34 @@ ```typescript import "dotenv/config"; -import { Keypair, ComputeBudgetProgram, Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createRpc, bn } from "@lightprotocol/stateless.js"; import { - createMint, - mintTo, - decompress, + Keypair, + ComputeBudgetProgram, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { + createMintInterface, + createAtaInterface, + mintToInterface, + decompressInterface, createWrapInstruction, getAssociatedTokenAddressInterface, createAtaInterfaceIdempotent, getSplInterfaceInfos, } from "@lightprotocol/compressed-token"; -import { createAssociatedTokenAccount } from "@solana/spl-token"; +import { + createAssociatedTokenAccount, + TOKEN_2022_PROGRAM_ID, +} from "@solana/spl-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); +// const rpc = createRpc(RPC_URL); // localnet: -// const rpc = createRpc(); +const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( @@ -29,18 +38,28 @@ const payer = Keypair.fromSecretKey( (async function () { // Setup: Get SPL tokens (needed to wrap) - const { mint } = await createMint(rpc, payer, payer.publicKey, 9); + const { mint } = await createMintInterface(rpc, payer, payer, null, 9); + await createAtaInterface(rpc, payer, mint, payer.publicKey); + const destination = getAssociatedTokenAddressInterface( + mint, + payer.publicKey + ); + await mintToInterface(rpc, payer, mint, destination, payer, 1000); const splAta = await createAssociatedTokenAccount( rpc, payer, mint, - payer.publicKey + payer.publicKey, + undefined, + TOKEN_2022_PROGRAM_ID ); - await mintTo(rpc, payer, mint, payer.publicKey, payer, bn(1000)); - await decompress(rpc, payer, mint, bn(1000), payer, splAta); + await decompressInterface(rpc, payer, payer, mint, 1000); // Create wrap instruction - const lightTokenAta = getAssociatedTokenAddressInterface(mint, payer.publicKey); + const lightTokenAta = getAssociatedTokenAddressInterface( + mint, + payer.publicKey + ); await createAtaInterfaceIdempotent(rpc, payer, mint, payer.publicKey); const splInterfaceInfos = await getSplInterfaceInfos(rpc, mint); @@ -55,7 +74,7 @@ const payer = Keypair.fromSecretKey( lightTokenAta, payer.publicKey, mint, - bn(500), + 500, splInterfaceInfo, 9, // decimals - must match the mint decimals payer.publicKey From 0e70c7393f8083f7a5058fb10cd12ef406f675fb Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Fri, 20 Mar 2026 00:59:05 +0000 Subject: [PATCH 12/19] add all --- .../compressed-token/approve/action.mdx | 39 ---------- .../compress-spl-account/action.mdx | 51 ------------- .../compressed-token/compress/action.mdx | 39 ---------- .../compressed-token/create-mint/action.mdx | 35 --------- .../create-mint/instruction.mdx | 72 ------------------- .../create-token-pool/action.mdx | 36 ---------- .../compressed-token/decompress/action.mdx | 37 ---------- .../merge-token-accounts/action.mdx | 38 ---------- .../compressed-token/mint-to/action.mdx | 36 ---------- .../compressed-token/mint-to/instruction.mdx | 70 ------------------ .../compressed-token/revoke/action.mdx | 40 ----------- .../compressed-token/transfer/action.mdx | 38 ---------- 12 files changed, 531 deletions(-) delete mode 100644 snippets/code-snippets/compressed-token/approve/action.mdx delete mode 100644 snippets/code-snippets/compressed-token/compress-spl-account/action.mdx delete mode 100644 snippets/code-snippets/compressed-token/compress/action.mdx delete mode 100644 snippets/code-snippets/compressed-token/create-mint/action.mdx delete mode 100644 snippets/code-snippets/compressed-token/create-mint/instruction.mdx delete mode 100644 snippets/code-snippets/compressed-token/create-token-pool/action.mdx delete mode 100644 snippets/code-snippets/compressed-token/decompress/action.mdx delete mode 100644 snippets/code-snippets/compressed-token/merge-token-accounts/action.mdx delete mode 100644 snippets/code-snippets/compressed-token/mint-to/action.mdx delete mode 100644 snippets/code-snippets/compressed-token/mint-to/instruction.mdx delete mode 100644 snippets/code-snippets/compressed-token/revoke/action.mdx delete mode 100644 snippets/code-snippets/compressed-token/transfer/action.mdx diff --git a/snippets/code-snippets/compressed-token/approve/action.mdx b/snippets/code-snippets/compressed-token/approve/action.mdx deleted file mode 100644 index 357a099..0000000 --- a/snippets/code-snippets/compressed-token/approve/action.mdx +++ /dev/null @@ -1,39 +0,0 @@ -```typescript -import "dotenv/config"; -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMint, mintTo, approve } from "@lightprotocol/compressed-token"; -import BN from "bn.js"; -import { homedir } from "os"; -import { readFileSync } from "fs"; - -// devnet: -const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; -// localnet: -// const RPC_URL = undefined; -const payer = Keypair.fromSecretKey( - new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) - ) -); - -(async function () { - // devnet: - const rpc = createRpc(RPC_URL); - // localnet: - // const rpc = createRpc(); - - // Setup: Create mint and mint tokens - const { mint } = await createMint(rpc, payer, payer.publicKey, 9); - const owner = Keypair.generate(); - await mintTo(rpc, payer, mint, owner.publicKey, payer, 1_000_000_000); - - // Approve delegate - const delegate = Keypair.generate(); - const tx = await approve(rpc, payer, mint, new BN(500_000_000), owner, delegate.publicKey); - - console.log("Mint:", mint.toBase58()); - console.log("Delegate:", delegate.publicKey.toBase58()); - console.log("Tx:", tx); -})(); -``` diff --git a/snippets/code-snippets/compressed-token/compress-spl-account/action.mdx b/snippets/code-snippets/compressed-token/compress-spl-account/action.mdx deleted file mode 100644 index 892342f..0000000 --- a/snippets/code-snippets/compressed-token/compress-spl-account/action.mdx +++ /dev/null @@ -1,51 +0,0 @@ -```typescript -import "dotenv/config"; -import { Keypair } from "@solana/web3.js"; -import { createRpc, bn } from "@lightprotocol/stateless.js"; -import { createMint, compressSplTokenAccount } from "@lightprotocol/compressed-token"; -import { createAssociatedTokenAccount, mintTo, TOKEN_PROGRAM_ID } from "@solana/spl-token"; -import { homedir } from "os"; -import { readFileSync } from "fs"; - -// devnet: -const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; -// localnet: -// const RPC_URL = undefined; -const payer = Keypair.fromSecretKey( - new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) - ) -); - -(async function () { - // devnet: - const rpc = createRpc(RPC_URL); - // localnet: - // const rpc = createRpc(); - - // Setup: Create mint and SPL token account with tokens - const { mint } = await createMint(rpc, payer, payer.publicKey, 9); - const owner = Keypair.generate(); - const tokenAccount = await createAssociatedTokenAccount( - rpc, - payer, - mint, - owner.publicKey, - undefined, - TOKEN_PROGRAM_ID - ); - await mintTo(rpc, payer, mint, tokenAccount, payer, bn(1_000_000_000).toNumber()); - - // Compress entire SPL token account balance - const tx = await compressSplTokenAccount( - rpc, - payer, - mint, - owner, - tokenAccount - ); - - console.log("Mint:", mint.toBase58()); - console.log("Tx:", tx); -})(); -``` diff --git a/snippets/code-snippets/compressed-token/compress/action.mdx b/snippets/code-snippets/compressed-token/compress/action.mdx deleted file mode 100644 index d7d33b5..0000000 --- a/snippets/code-snippets/compressed-token/compress/action.mdx +++ /dev/null @@ -1,39 +0,0 @@ -```typescript -import "dotenv/config"; -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMint, mintTo, decompress, compress } from "@lightprotocol/compressed-token"; -import { createAssociatedTokenAccount } from "@solana/spl-token"; -import { homedir } from "os"; -import { readFileSync } from "fs"; - -// devnet: -const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; -// localnet: -// const RPC_URL = undefined; -const payer = Keypair.fromSecretKey( - new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) - ) -); - -(async function () { - // devnet: - const rpc = createRpc(RPC_URL); - // localnet: - // const rpc = createRpc(); - - // Setup: Get SPL tokens (needed to compress) - const { mint } = await createMint(rpc, payer, payer.publicKey, 9); - const splAta = await createAssociatedTokenAccount(rpc, payer, mint, payer.publicKey); - await mintTo(rpc, payer, mint, payer.publicKey, payer, 1_000_000_000); - await decompress(rpc, payer, mint, 1_000_000_000, payer, splAta); - - // Compress SPL tokens - const recipient = Keypair.generate(); - const tx = await compress(rpc, payer, mint, 500_000_000, payer, splAta, recipient.publicKey); - - console.log("Mint:", mint.toBase58()); - console.log("Tx:", tx); -})(); -``` diff --git a/snippets/code-snippets/compressed-token/create-mint/action.mdx b/snippets/code-snippets/compressed-token/create-mint/action.mdx deleted file mode 100644 index 186789d..0000000 --- a/snippets/code-snippets/compressed-token/create-mint/action.mdx +++ /dev/null @@ -1,35 +0,0 @@ -```typescript -import "dotenv/config"; -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMint } 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!}`; -// localnet: -// const RPC_URL = undefined; -const payer = Keypair.fromSecretKey( - new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) - ) -); - -(async function () { - // devnet: - const rpc = createRpc(RPC_URL); - // localnet: - // const rpc = createRpc(); - - const { mint, transactionSignature } = await createMint( - rpc, - payer, - payer.publicKey, - 9 - ); - - console.log("Mint:", mint.toBase58()); - console.log("Tx:", transactionSignature); -})(); -``` diff --git a/snippets/code-snippets/compressed-token/create-mint/instruction.mdx b/snippets/code-snippets/compressed-token/create-mint/instruction.mdx deleted file mode 100644 index 47be621..0000000 --- a/snippets/code-snippets/compressed-token/create-mint/instruction.mdx +++ /dev/null @@ -1,72 +0,0 @@ -```typescript -import "dotenv/config"; -import { - Keypair, - ComputeBudgetProgram, - PublicKey, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { - createRpc, - getBatchAddressTreeInfo, - selectStateTreeInfo, - LIGHT_TOKEN_PROGRAM_ID, -} from "@lightprotocol/stateless.js"; -import { createMintInstruction } from "@lightprotocol/compressed-token"; -import { homedir } from "os"; -import { readFileSync } from "fs"; - -const COMPRESSED_MINT_SEED = Buffer.from("compressed_mint"); - -function findMintAddress(mintSigner: PublicKey): [PublicKey, number] { - return PublicKey.findProgramAddressSync( - [COMPRESSED_MINT_SEED, mintSigner.toBuffer()], - LIGHT_TOKEN_PROGRAM_ID - ); -} - -// 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 () { - const mintSigner = Keypair.generate(); - const addressTreeInfo = getBatchAddressTreeInfo(); - const stateTreeInfo = selectStateTreeInfo(await rpc.getStateTreeInfos()); - const [mintPda] = findMintAddress(mintSigner.publicKey); - - const validityProof = await rpc.getValidityProofV2( - [], - [{ address: mintPda.toBytes(), treeInfo: addressTreeInfo }] - ); - - const ix = createMintInstruction( - mintSigner.publicKey, - 9, - payer.publicKey, - null, - payer.publicKey, - validityProof, - addressTreeInfo, - stateTreeInfo - ); - - const tx = new Transaction().add( - ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 }), - ix - ); - const signature = await sendAndConfirmTransaction(rpc, tx, [payer, mintSigner]); - - console.log("Mint:", mintPda.toBase58()); - console.log("Tx:", signature); -})(); -``` diff --git a/snippets/code-snippets/compressed-token/create-token-pool/action.mdx b/snippets/code-snippets/compressed-token/create-token-pool/action.mdx deleted file mode 100644 index 5597544..0000000 --- a/snippets/code-snippets/compressed-token/create-token-pool/action.mdx +++ /dev/null @@ -1,36 +0,0 @@ -```typescript -import "dotenv/config"; -import { Keypair, PublicKey } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createSplInterface } from "@lightprotocol/compressed-token"; -import { createMint as createSplMint, TOKEN_PROGRAM_ID } from "@solana/spl-token"; -import { homedir } from "os"; -import { readFileSync } from "fs"; - -// devnet: -const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; -// localnet: -// const RPC_URL = undefined; -const payer = Keypair.fromSecretKey( - new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) - ) -); - -(async function () { - // devnet: - const rpc = createRpc(RPC_URL); - // localnet: - // const rpc = createRpc(); - - // Setup: Create existing SPL mint - const mintKeypair = Keypair.generate(); - await createSplMint(rpc, payer, payer.publicKey, null, 9, mintKeypair, undefined, TOKEN_PROGRAM_ID); - - // Create SPL interface for existing mint - const tx = await createSplInterface(rpc, payer, mintKeypair.publicKey); - - console.log("Mint:", mintKeypair.publicKey.toBase58()); - console.log("Tx:", tx); -})(); -``` diff --git a/snippets/code-snippets/compressed-token/decompress/action.mdx b/snippets/code-snippets/compressed-token/decompress/action.mdx deleted file mode 100644 index 8bd7264..0000000 --- a/snippets/code-snippets/compressed-token/decompress/action.mdx +++ /dev/null @@ -1,37 +0,0 @@ -```typescript -import "dotenv/config"; -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMint, mintTo, decompress } from "@lightprotocol/compressed-token"; -import { createAssociatedTokenAccount } from "@solana/spl-token"; -import { homedir } from "os"; -import { readFileSync } from "fs"; - -// devnet: -const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; -// localnet: -// const RPC_URL = undefined; -const payer = Keypair.fromSecretKey( - new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) - ) -); - -(async function () { - // devnet: - const rpc = createRpc(RPC_URL); - // localnet: - // const rpc = createRpc(); - - // Setup: Create mint and mint compressed tokens - const { mint } = await createMint(rpc, payer, payer.publicKey, 9); - await mintTo(rpc, payer, mint, payer.publicKey, payer, 1_000_000_000); - const splAta = await createAssociatedTokenAccount(rpc, payer, mint, payer.publicKey); - - // Decompress to SPL tokens - const tx = await decompress(rpc, payer, mint, 500_000_000, payer, splAta); - - console.log("Mint:", mint.toBase58()); - console.log("Tx:", tx); -})(); -``` diff --git a/snippets/code-snippets/compressed-token/merge-token-accounts/action.mdx b/snippets/code-snippets/compressed-token/merge-token-accounts/action.mdx deleted file mode 100644 index eea48df..0000000 --- a/snippets/code-snippets/compressed-token/merge-token-accounts/action.mdx +++ /dev/null @@ -1,38 +0,0 @@ -```typescript -import "dotenv/config"; -import { Keypair } from "@solana/web3.js"; -import { createRpc, bn } from "@lightprotocol/stateless.js"; -import { createMint, mintTo, mergeTokenAccounts } 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!}`; -// localnet: -// const RPC_URL = undefined; -const payer = Keypair.fromSecretKey( - new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) - ) -); - -(async function () { - // devnet: - const rpc = createRpc(RPC_URL); - // localnet: - // const rpc = createRpc(); - - // Setup: Create mint and mint multiple times to create multiple accounts - const { mint } = await createMint(rpc, payer, payer.publicKey, 9); - const owner = Keypair.generate(); - await mintTo(rpc, payer, mint, owner.publicKey, payer, bn(100_000_000)); - await mintTo(rpc, payer, mint, owner.publicKey, payer, bn(200_000_000)); - await mintTo(rpc, payer, mint, owner.publicKey, payer, bn(300_000_000)); - - // Merge all accounts for owner - const tx = await mergeTokenAccounts(rpc, payer, mint, owner); - - console.log("Mint:", mint.toBase58()); - console.log("Tx:", tx); -})(); -``` diff --git a/snippets/code-snippets/compressed-token/mint-to/action.mdx b/snippets/code-snippets/compressed-token/mint-to/action.mdx deleted file mode 100644 index be0a05b..0000000 --- a/snippets/code-snippets/compressed-token/mint-to/action.mdx +++ /dev/null @@ -1,36 +0,0 @@ -```typescript -import "dotenv/config"; -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMint, mintTo } 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!}`; -// localnet: -// const RPC_URL = undefined; -const payer = Keypair.fromSecretKey( - new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) - ) -); - -(async function () { - // devnet: - const rpc = createRpc(RPC_URL); - // localnet: - // const rpc = createRpc(); - - // Setup: Create mint - const { mint } = await createMint(rpc, payer, payer.publicKey, 9); - - // Mint compressed tokens - const recipient = Keypair.generate(); - const tx = await mintTo(rpc, payer, mint, recipient.publicKey, payer, 1_000_000_000); - - console.log("Mint:", mint.toBase58()); - console.log("Recipient:", recipient.publicKey.toBase58()); - console.log("Tx:", tx); -})(); -``` diff --git a/snippets/code-snippets/compressed-token/mint-to/instruction.mdx b/snippets/code-snippets/compressed-token/mint-to/instruction.mdx deleted file mode 100644 index bad8788..0000000 --- a/snippets/code-snippets/compressed-token/mint-to/instruction.mdx +++ /dev/null @@ -1,70 +0,0 @@ -```typescript -import "dotenv/config"; -import { Keypair, ComputeBudgetProgram, Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; -import { createRpc, bn, DerivationMode } from "@lightprotocol/stateless.js"; -import { - createMintInterface, - createAtaInterface, - createMintToInterfaceInstruction, - getMintInterface, - 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 () { - const { mint } = await createMintInterface(rpc, payer, payer, null, 9); - - const recipient = Keypair.generate(); - await createAtaInterface(rpc, payer, mint, recipient.publicKey); - const destination = getAssociatedTokenAddressInterface(mint, recipient.publicKey); - - const mintInterface = await getMintInterface(rpc, mint); - - let validityProof; - if (mintInterface.merkleContext) { - validityProof = await rpc.getValidityProofV2( - [ - { - hash: bn(mintInterface.merkleContext.hash), - leafIndex: mintInterface.merkleContext.leafIndex, - treeInfo: mintInterface.merkleContext.treeInfo, - proveByIndex: mintInterface.merkleContext.proveByIndex, - }, - ], - [], - DerivationMode.compressible - ); - } - - const ix = createMintToInterfaceInstruction( - mintInterface, - destination, - payer.publicKey, - payer.publicKey, - 1_000_000_000, - validityProof - ); - - const tx = new Transaction().add( - ComputeBudgetProgram.setComputeUnitLimit({ units: 500_000 }), - ix - ); - const signature = await sendAndConfirmTransaction(rpc, tx, [payer]); - - console.log("Mint:", mint.toBase58()); - console.log("Tx:", signature); -})(); -``` diff --git a/snippets/code-snippets/compressed-token/revoke/action.mdx b/snippets/code-snippets/compressed-token/revoke/action.mdx deleted file mode 100644 index 52dfef4..0000000 --- a/snippets/code-snippets/compressed-token/revoke/action.mdx +++ /dev/null @@ -1,40 +0,0 @@ -```typescript -import "dotenv/config"; -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMint, mintTo, approve, revoke } from "@lightprotocol/compressed-token"; -import BN from "bn.js"; -import { homedir } from "os"; -import { readFileSync } from "fs"; - -// devnet: -const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; -// localnet: -// const RPC_URL = undefined; -const payer = Keypair.fromSecretKey( - new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) - ) -); - -(async function () { - // devnet: - const rpc = createRpc(RPC_URL); - // localnet: - // const rpc = createRpc(); - - // Setup: Create mint, mint tokens, and approve delegate - const { mint } = await createMint(rpc, payer, payer.publicKey, 9); - const owner = Keypair.generate(); - await mintTo(rpc, payer, mint, owner.publicKey, payer, 1_000_000_000); - const delegate = Keypair.generate(); - await approve(rpc, payer, mint, new BN(500_000_000), owner, delegate.publicKey); - - // Get delegated accounts and revoke - const delegatedAccounts = await rpc.getCompressedTokenAccountsByDelegate(delegate.publicKey, { mint }); - const tx = await revoke(rpc, payer, delegatedAccounts.items, owner); - - console.log("Mint:", mint.toBase58()); - console.log("Tx:", tx); -})(); -``` diff --git a/snippets/code-snippets/compressed-token/transfer/action.mdx b/snippets/code-snippets/compressed-token/transfer/action.mdx deleted file mode 100644 index ff7ab41..0000000 --- a/snippets/code-snippets/compressed-token/transfer/action.mdx +++ /dev/null @@ -1,38 +0,0 @@ -```typescript -import "dotenv/config"; -import { Keypair } from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { createMint, mintTo, transfer } 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!}`; -// localnet: -// const RPC_URL = undefined; -const payer = Keypair.fromSecretKey( - new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) - ) -); - -(async function () { - // devnet: - const rpc = createRpc(RPC_URL); - // localnet: - // const rpc = createRpc(); - - // Setup: Create mint and mint tokens - const { mint } = await createMint(rpc, payer, payer.publicKey, 9); - const sender = Keypair.generate(); - await mintTo(rpc, payer, mint, sender.publicKey, payer, 1_000_000_000); - - // Transfer compressed tokens - const recipient = Keypair.generate(); - const tx = await transfer(rpc, payer, mint, 500_000_000, sender, recipient.publicKey); - - console.log("Mint:", mint.toBase58()); - console.log("Recipient:", recipient.publicKey.toBase58()); - console.log("Tx:", tx); -})(); -``` From 7af253445bf5e292c1e9b3482c803b7f7b6dc1ea Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Fri, 20 Mar 2026 02:14:13 +0000 Subject: [PATCH 13/19] update llm and skill --- ai-tools/agent-skills.mdx | 18 +-- api-reference/solana-to-light-comparison.mdx | 4 +- light-token/payments/wrap-unwrap.mdx | 2 +- llms.txt | 44 ++++-- pda/compressed-pdas/nullifier-pda.mdx | 2 +- scripts/copy-extensions-snippets.sh | 54 +++++++ scripts/copy-light-token-snippets.sh | 4 +- scripts/copy-program-snippets.sh | 6 +- scripts/copy-rust-snippets.sh | 4 +- scripts/generate-llms-txt.js | 23 +-- skill.md | 75 +++++----- snippets/ai-prompts/all-prompts.mdx | 134 +++++++++++++----- snippets/ai-prompts/wallets/privy.mdx | 8 +- .../rust-client/approve-instruction.mdx | 1 + .../rust-client/revoke-instruction.mdx | 1 + .../burn/rust-client/instruction.mdx | 3 +- .../create-mint/rust-client/instruction.mdx | 2 +- .../mint-to/rust-client/instruction.mdx | 3 +- .../rust-client/instruction.mdx | 4 +- .../payments/receive/receive.mdx | 17 ++- .../payments/send/batch-send.mdx | 9 +- .../payments/send/payment-with-memo.mdx | 10 +- .../payments/send/send-action.mdx | 14 +- .../payments/send/send-instruction.mdx | 14 +- .../payments/send/sign-all-transactions.mdx | 12 +- .../spend-permissions/delegate-full-flow.mdx | 38 +---- .../payments/verify/get-balance.mdx | 18 +-- .../payments/verify/get-history.mdx | 13 +- .../code-snippets/privy/balances/nodejs.mdx | 74 ++++++---- .../code-snippets/privy/balances/react.mdx | 30 +++- .../code-snippets/privy/receive/nodejs.mdx | 61 -------- .../code-snippets/privy/receive/react.mdx | 59 -------- .../code-snippets/privy/transfer/nodejs.mdx | 2 +- .../code-snippets/privy/unwrap/nodejs.mdx | 4 +- snippets/code-snippets/privy/unwrap/react.mdx | 4 +- snippets/code-snippets/privy/wrap/nodejs.mdx | 2 +- snippets/code-snippets/privy/wrap/react.mdx | 4 +- .../wallet-adapter/balances/react.mdx | 23 ++- .../wallet-adapter/receive/react.mdx | 55 ------- .../transaction-history/react.mdx | 4 +- .../wallet-adapter/transfer/react.mdx | 20 ++- .../wallet-adapter/unwrap/react.mdx | 8 +- .../wallet-adapter/wrap/react.mdx | 8 +- .../light-token-client-examples-table.mdx | 20 +++ .../light-token-program-examples-table.mdx | 4 +- 45 files changed, 419 insertions(+), 500 deletions(-) create mode 100755 scripts/copy-extensions-snippets.sh diff --git a/ai-tools/agent-skills.mdx b/ai-tools/agent-skills.mdx index cccabcc..09744ba 100644 --- a/ai-tools/agent-skills.mdx +++ b/ai-tools/agent-skills.mdx @@ -36,15 +36,15 @@ npx skills add Lightprotocol/skills | Use case | Skill | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | -| Build rent-free Solana programs with Light SDK (Anchor or Pinocchio). Includes router integration. | [light-sdk](https://github.com/Lightprotocol/skills/tree/main/skills/light-sdk) | -| Use Light Token client SDKs (TypeScript and Rust) for mints, ATAs, transfers | [light-token-client](https://github.com/Lightprotocol/skills/tree/main/skills/light-token-client) | -| Stream account state via Laserstream gRPC | [data-streaming](https://github.com/Lightprotocol/skills/tree/main/skills/data-streaming) | -| Skill for payment flows using Light Token APIs for sponsored rent-exemption. | [payments](https://github.com/Lightprotocol/skills/tree/main/skills/payments) | -| Airdrops, DePIN, token distribution | [token-distribution](https://github.com/Lightprotocol/skills/tree/main/skills/token-distribution) | -| Anti-double-spend nullifiers for Privacy-preserving ZK programs | [zk-nullifier](https://github.com/Lightprotocol/skills/tree/main/skills/zk-nullifier) | -| Testing programs and clients on localnet, devnet, mainnet | [testing](https://github.com/Lightprotocol/skills/tree/main/skills/testing) | -| For per-user state, DePIN nodes, and infrequently accessed app state with compressed PDAs | [solana-compression](https://github.com/Lightprotocol/skills/tree/main/skills/solana-compression) | -| Help with Debugging and Questions via DeepWiki MCP | [ask-mcp](https://github.com/Lightprotocol/skills/tree/main/skills/ask-mcp) | +| For stablecoin payment flows and wallet integrations on Solana. | [payments](https://github.com/Lightprotocol/skills/tree/main/skills/payments) | +| For client development with Light Token APIs on Solana. | [light-token-client](https://github.com/Lightprotocol/skills/tree/main/skills/light-token-client) | +| For Solana program development with tokens and PDAs. | [light-sdk](https://github.com/Lightprotocol/skills/tree/main/skills/light-sdk) | +| For data pipelines, aggregators, or indexers, real-time account state streaming on Solana with light account hot/cold lifecycle tracking | [data-streaming](https://github.com/Lightprotocol/skills/tree/main/skills/data-streaming) | +| For token distribution on Solana 5000x cheaper than SPL (rewards, airdrops, depins, ...) | [token-distribution](https://github.com/Lightprotocol/skills/tree/main/skills/token-distribution) | +| For custom ZK Solana programs and privacy-preserving applications to prevent double spending | [zk-nullifier](https://github.com/Lightprotocol/skills/tree/main/skills/zk-nullifier) | +| For program development on Solana with infrequently accessed state, such as per-user state, DePIN registrations, ... | [solana-compression](https://github.com/Lightprotocol/skills/tree/main/skills/solana-compression) | +| For testing with Light Protocol programs and clients on localnet, devnet, and mainnet validation | [testing](https://github.com/Lightprotocol/skills/tree/main/skills/testing) | +| For questions about compressed accounts, Light SDK, Solana development, Claude Code features, or agent skills | [ask-mcp](https://github.com/Lightprotocol/skills/tree/main/skills/ask-mcp) | > View all skills here: https://github.com/Lightprotocol/skills. diff --git a/api-reference/solana-to-light-comparison.mdx b/api-reference/solana-to-light-comparison.mdx index b10d053..e217bfc 100644 --- a/api-reference/solana-to-light-comparison.mdx +++ b/api-reference/solana-to-light-comparison.mdx @@ -1163,7 +1163,7 @@ invoke(&ix, &[mint, rent_sysvar])?; Create a rent-free associated token account via CPI. > [Guide](/light-token/cookbook/create-ata) | -> [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/create-ata/src/lib.rs) | +> [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/create-associated-token-account/src/lib.rs) | > [Source](https://docs.rs/light-token) @@ -1495,7 +1495,7 @@ token_metadata_initialize( ### Create associated token account > [Guide](/light-token/cookbook/create-ata) | -> [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/create-ata) | +> [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/create-associated-token-account) | > [Source](https://docs.rs/light-token) diff --git a/light-token/payments/wrap-unwrap.mdx b/light-token/payments/wrap-unwrap.mdx index 1641df1..9289fa2 100644 --- a/light-token/payments/wrap-unwrap.mdx +++ b/light-token/payments/wrap-unwrap.mdx @@ -1,7 +1,7 @@ --- title: "Wrap and Unwrap" sidebarTitle: "Wrap and Unwrap" -description: "Move tokens between SPL / Token 2022 and Light Token accounts for CEX on-ramps, off-ramps, and interoperability." +description: "Move tokens between SPL / Token 2022 and Light Token accounts for interoperability with applications that don't support Light Token yet." keywords: ["wrap tokens solana", "unwrap tokens solana", "spl to light token", "cex onramp solana", "token interoperability"] --- diff --git a/llms.txt b/llms.txt index 49a392a..fd5a021 100644 --- a/llms.txt +++ b/llms.txt @@ -54,7 +54,7 @@ Comparing creation cost and CU usage: - **Agent Skills:** [light-sdk](https://github.com/Lightprotocol/skills/tree/main/skills/light-sdk): For Solana program development with tokens and PDAs, Light is 200x cheaper than SPL/ Solana and has minimal code differences - **Agent Skills:** [light-token-client](https://github.com/Lightprotocol/skills/tree/main/skills/light-token-client): For client development with tokens on Solana, Light Token is 200x cheaper than SPL and has minimal changes - **Agent Skills:** [data-streaming](https://github.com/Lightprotocol/skills/tree/main/skills/data-streaming): For data pipelines, aggregators, or indexers, real-time account state streaming on Solana with light account hot/cold lifecycle tracking -- **Agent Skills:** [payments-and-wallets](https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets): For stablecoin payment flows and wallet integrations on Solana. +- **Agent Skills:** [payments](https://github.com/Lightprotocol/skills/tree/main/skills/payments): Skill for payment flows using Light Token APIs for sponsored rent-exemption. - **Agent Skills:** [token-distribution](https://github.com/Lightprotocol/skills/tree/main/skills/token-distribution): For token distribution on Solana 5000x cheaper than SPL (rewards, airdrops, depins, ...) - **Agent Skills:** [zk-nullifier](https://github.com/Lightprotocol/skills/tree/main/skills/zk-nullifier): For custom ZK Solana programs and privacy-preserving applications to prevent double spending. - **Agent Skills:** [testing](https://github.com/Lightprotocol/skills/tree/main/skills/testing): For testing with Light Protocol programs and clients on localnet, devnet, and mainnet validation @@ -82,7 +82,7 @@ Comparing creation cost and CU usage: - [Receive Payments](https://www.zkcompression.com/light-token/payments/receive-payments.md): Prepare to receive token payments by loading cold accounts and sharing your associated token account address. - **Verify Payments:** [Verify Payments](https://www.zkcompression.com/light-token/payments/verify-payments.md): Query token balances and transaction history to verify incoming payments. - **Verify Payments:** [Verify Address](https://www.zkcompression.com/light-token/payments/verify-recipient-address.md): Verify recipient addresses before sending payments. Address validation prevents sending tokens to invalid or unexpected account types. -- [Wrap and Unwrap](https://www.zkcompression.com/light-token/payments/wrap-unwrap.md): Move tokens between SPL / Token 2022 and Light Token accounts for CEX on-ramps, off-ramps, and interoperability. +- [Wrap and Unwrap](https://www.zkcompression.com/light-token/payments/wrap-unwrap.md): Move tokens between SPL / Token 2022 and Light Token accounts for interoperability with applications that don't support Light Token yet. - **Advanced:** [Spend Permissions via Delegation](https://www.zkcompression.com/light-token/payments/spend-permissions.md): Delegate token spending to a third party with an amount cap. The delegate can transfer tokens on behalf of the owner up to the approved amount, without the owner signing each transaction. - **Advanced:** [Create Nullifier PDAs](https://www.zkcompression.com/pda/compressed-pdas/nullifier-pda.md): Create rent-free nullifier PDAs to prevent duplicate actions. - [Production Readiness](https://www.zkcompression.com/light-token/payments/production-readiness.md): Non-exhaustive checklist for deploying Light Token payment flows to production, including RPC infrastructure, error handling, and security. @@ -103,18 +103,31 @@ Comparing creation cost and CU usage: ## Light Token Basics - [The Light Token Program](https://www.zkcompression.com/light-token/welcome.md): High-performance token standard that is functionally equivalent to SPL while reducing account creation cost by 200x and being more CU efficient on hot paths. The Light Token SDK keeps code changes minimal and is a superset of the SPL-token API. -- [Create Mint Account with Token Metadata](https://www.zkcompression.com/light-token/cookbook/create-mint.md): Program and client guides to create a mint with token metadata. For existing SPL or Token 2022 mints add an interface PDA for interoperability. Includes step-by-step implementation and full code examples. +- **Mint Accounts:** [Create Mint Account with Token Metadata](https://www.zkcompression.com/light-token/cookbook/create-mint.md): Create a Light mint with token metadata, or create SPL and Token 2022 mints with interface PDA for interoperability. +- **Mint Accounts:** [Add Interface PDA to Existing SPL / Token 2022 Mints](https://www.zkcompression.com/light-token/cookbook/add-interface-pda.md): Create an interface PDA for an existing SPL or Token 2022 mint for interoperability with Light Token. Does not require mint authority. - [Create Associated Light Token Accounts](https://www.zkcompression.com/light-token/cookbook/create-ata.md): Client and program guide to create associated Light Token accounts. Includes step-by-step implementation and full code examples. - [Create Light Token Account](https://www.zkcompression.com/light-token/cookbook/create-token-account.md): Client and program guide to create Light Token accounts. Includes step-by-step implementation and full code examples. - [Mint to Light Token Accounts](https://www.zkcompression.com/light-token/cookbook/mint-to.md): Client and program guide to mint tokens to a account. Includes step-by-step implementation and full code examples. -- [Transfer Interface](https://www.zkcompression.com/light-token/cookbook/transfer-interface.md): Program and client guide for transfers between Light Token and SPL token accounts. The interface detects account types and invokes the right programs. -- [Transfer Checked](https://www.zkcompression.com/light-token/cookbook/transfer-checked.md): Rust client guide to transfer Light Tokens with decimal validation. Includes step-by-step implementation and full code examples. -- [Approve and Revoke Delegates](https://www.zkcompression.com/light-token/cookbook/approve-revoke.md): Rust client guide to approve and revoke delegates for Light Token accounts. Includes step-by-step implementation and full code examples. +- [Transfer Interface](https://www.zkcompression.com/light-token/cookbook/transfer-interface.md): Transfer tokens between Light Token, SPL and Token 2022 accounts. The interface checks decimals under the hood and detects account types to invoke the right programs. +- [Transfer Checked](https://www.zkcompression.com/light-token/cookbook/transfer-checked.md): Program CPI guide for Light Token transfer with decimal validation. Includes step-by-step implementation and full code examples. +- **Delegates:** [Approve and Revoke Delegates](https://www.zkcompression.com/light-token/cookbook/approve-revoke.md): Guide to approve and revoke delegates for Light Token accounts. Includes step-by-step implementation and full code examples. +- **Delegates:** [Delegated Transfer](https://www.zkcompression.com/light-token/cookbook/transfer-delegated.md): Transfer tokens as an approved delegate. The delegate signs instead of the owner, spending within the approved allowance. - [Freeze and Thaw Light Token Accounts](https://www.zkcompression.com/light-token/cookbook/freeze-thaw.md): Rust client guide to freeze and thaw Light Token accounts. Includes step-by-step implementation and full code examples. - [Wrap & Unwrap SPL/Token 2022 <> Light Token](https://www.zkcompression.com/light-token/cookbook/wrap-unwrap.md): Move tokens between SPL/Token 2022 token and Light Token accounts. Use to interact with applications that only support SPL/Token 2022. - [Load Token Balances to Light Associated Token Account](https://www.zkcompression.com/light-token/cookbook/load-ata.md): Unify token balances from compressed tokens (cold Light Tokens), SPL, and Token 2022 to one light ATA. - [Close Light Token Account](https://www.zkcompression.com/light-token/cookbook/close-token-account.md): Program guide to close Light Token accounts via CPI. Includes step-by-step implementation and full code examples. - [Burn Light Tokens](https://www.zkcompression.com/light-token/cookbook/burn.md): Rust client guide to burn Light Tokens. Includes step-by-step implementation and full code examples. +- [Token extensions](https://www.zkcompression.com/light-token/extensions/overview.md): Most Token 2022 extensions are supported by Light Token to add features through extra instructions to a token mint or token account. +- [Metadata and metadata pointer](https://www.zkcompression.com/light-token/extensions/metadata-and-metadata-pointer.md): Configure the MetadataPointer and TokenMetadata extensions to store token name, symbol, and URI on a Token 2022 mint using Light Token. +- [Transfer fees](https://www.zkcompression.com/light-token/extensions/transfer-fees.md): Configure the TransferFeeConfig extension for automatic fee collection on every token transfer using Light Token. +- [Transfer hook](https://www.zkcompression.com/light-token/extensions/transfer-hook.md): Configure the TransferHook extension to attach a custom program callback to every token transfer using Light Token. +- [Interest bearing tokens](https://www.zkcompression.com/light-token/extensions/interest-bearing-tokens.md): Configure the InterestBearingConfig extension to display UI-adjusted balances that accrue interest over time using Light Token. +- [Default account state](https://www.zkcompression.com/light-token/extensions/default-account-state.md): Configure the DefaultAccountState extension to set the initial state for newly created token accounts using Light Token. +- [Permanent delegate](https://www.zkcompression.com/light-token/extensions/permanent-delegate.md): Configure the PermanentDelegate extension to grant irrevocable transfer and burn authority over all token accounts using Light Token. +- [Close mint](https://www.zkcompression.com/light-token/extensions/close-mint.md): Configure the MintCloseAuthority extension to allow closing a mint account and reclaiming rent using Light Token. +- [Token groups and members](https://www.zkcompression.com/light-token/extensions/token-groups-and-members.md): Configure the GroupPointer, TokenGroup, GroupMemberPointer, and TokenGroupMember extensions to organize tokens into collections using Light Token. +- [Pausable mint](https://www.zkcompression.com/light-token/extensions/pausable-mint.md): Configure the Pausable extension to pause and resume all minting, burning, and transfers for a Token-2022 mint using Light Token. +- [Confidential transfer](https://www.zkcompression.com/light-token/extensions/confidential-transfer.md): Configure the ConfidentialTransferMint, ConfidentialTransferFeeConfig, and ConfidentialMintBurn extensions for encrypted token amounts using Light Token. - [Client examples](https://www.zkcompression.com/light-token/examples/client.md): TypeScript and Rust client examples for light-token SDK. - [Program examples](https://www.zkcompression.com/light-token/examples/program.md): Anchor program examples for light-token CPI. @@ -157,20 +170,21 @@ Comparing creation cost and CU usage: - [Support](https://www.zkcompression.com/support.md): Get expert help with Light-Token and ZK Compression. Discord community, Telegram, and Email support available. ## Examples for DeFi -- [cp-swap-reference](https://github.com/Lightprotocol/program-examples/tree/main/cp-swap-reference): Fork of Raydium AMM that creates markets without paying rent-exemption. -- [pinocchio-swap](https://github.com/Lightprotocol/program-examples/tree/main/pinocchio-swap): Light Token swap reference implementation. -- [token-swap](https://github.com/Lightprotocol/program-examples/tree/main/token-swap): AMM with liquidity pools and swaps. -- [escrow](https://github.com/Lightprotocol/program-examples/tree/main/escrow): Peer-to-peer light-token swap with offer/accept flow. -- [fundraiser](https://github.com/Lightprotocol/program-examples/tree/main/fundraiser): Token fundraiser with target, deadline, and refunds. -- [create-and-transfer](https://github.com/Lightprotocol/program-examples/tree/main/create-and-transfer): Create account via macro and transfer via CPI. -- [light-token-minter](https://github.com/Lightprotocol/program-examples/tree/main/light-token-minter): Create light-mints with metadata, mint tokens. +- [cp-swap-reference](https://github.com/Lightprotocol/cp-swap-reference): Fork of Raydium AMM that creates markets without paying rent-exemption. +- [pinocchio-swap](https://github.com/Lightprotocol/examples-light-token/tree/main/pinocchio/swap): Light Token swap reference implementation. +- [token-swap](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/token-swap): AMM with liquidity pools and swaps. +- [escrow](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/escrow): Peer-to-peer light-token swap with offer/accept flow. +- [fundraiser](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/fundraiser): Token fundraiser with target, deadline, and refunds. +- [create-and-transfer](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/create-and-transfer): Create account via macro and transfer via CPI. +- [light-token-minter](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/light-token-minter): Create light-mints with metadata, mint tokens. ## Examples for Payments and Wallets -- [payments-and-wallets](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments-and-wallets): Wallet integrations and payment flows. +- [payments](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments): Wallet integrations and payment flows. - [sign-with-privy](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy): Light-token operations signed with Privy wallets. - [sign-with-wallet-adapter](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter): Light-token operations signed with Wallet Adapter. - [gasless-transactions](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions): Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees. -- [spl-to-light](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/spl-to-light): Transfer from SPL to Light via TransferInterface. +- [spl-to-light](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/instructions/spl_to_light_transfer.rs): Transfer from SPL to Light via TransferInterface. +- [streaming-tokens](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/streaming-tokens): Stream mint events using Laserstream. ## OpenAPI Specs - [api](https://www.zkcompression.com/openapi/api.yaml) diff --git a/pda/compressed-pdas/nullifier-pda.mdx b/pda/compressed-pdas/nullifier-pda.mdx index cd6410b..8afb27a 100644 --- a/pda/compressed-pdas/nullifier-pda.mdx +++ b/pda/compressed-pdas/nullifier-pda.mdx @@ -21,7 +21,7 @@ We also deployed a reference implementation to public networks so you can get st | **Example Tx** | [Solana Explorer](https://explorer.solana.com/tx/38fA6kbKRcYb5XSez9ffQzfCcMbMHcaJGseCogShNXC5SemQsEo88ZMSPCLP9xv9PG8qSJnhWvWFqSYJnfBMLrpB) | -For the usage example source code, see here: [create_nullifier.rs](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/actions/create_nullifier.rs#L25) +Example source code: [TypeScript](https://github.com/Lightprotocol/nullifier-program/tree/main/examples/action-create-nullifier.ts) | [Rust](https://github.com/Lightprotocol/nullifier-program/tree/main/examples/rust) diff --git a/scripts/copy-extensions-snippets.sh b/scripts/copy-extensions-snippets.sh new file mode 100755 index 0000000..d39e4c2 --- /dev/null +++ b/scripts/copy-extensions-snippets.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# Script to copy TypeScript extension examples to docs snippets. +# Source: examples-light-token-main/extensions +# Output: snippets/code-snippets/light-token/extensions/{name}/action.mdx + +EXAMPLES="/home/tilo/Workspace/examples-light-token-main/extensions" +SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/light-token/extensions" + +# Mapping of source-filename:output-dir +EXTENSIONS=( + "close-mint:close-mint" + "confidential-transfer:confidential-transfer" + "default-account-state:default-account-state" + "interest-bearing-tokens:interest-bearing" + "metadata-and-metadata-pointer:metadata-pointer" + "pausable-mint:pausable" + "permanent-delegate:permanent-delegate" + "token-groups-and-members:token-groups" + "transfer-fees:transfer-fees" + "transfer-hook:transfer-hook" +) + +# Function to wrap TypeScript code in markdown +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" + echo "Created: $output_file" +} + +echo "=== Processing extension snippets ===" +echo "" + +for mapping in "${EXTENSIONS[@]}"; do + source_name="${mapping%%:*}" + output_name="${mapping##*:}" + + src="$EXAMPLES/$source_name.ts" + if [ -f "$src" ]; then + wrap_typescript "$src" "$SNIPPETS_DIR/$output_name/action.mdx" + else + echo " WARNING: Not found - $src" + fi +done + +echo "" +echo "Done! Created snippets in: $SNIPPETS_DIR" +echo "" +echo "Files created:" +find "$SNIPPETS_DIR" -name "*.mdx" -type f | sort diff --git a/scripts/copy-light-token-snippets.sh b/scripts/copy-light-token-snippets.sh index c24d40c..b940786 100644 --- a/scripts/copy-light-token-snippets.sh +++ b/scripts/copy-light-token-snippets.sh @@ -3,8 +3,8 @@ # Script to copy TypeScript code from streaming-tokens to docs/snippets/code-snippets/light-token # Wraps each file in typescript markdown code blocks -EXAMPLES="/home/tilo/Workspace/streaming-tokens/typescript-client" -SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/light-token" +EXAMPLES="/home/tilo/Workspace/examples-light-token-main/typescript-client" +SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/light-token" # Recipes to process (matching directory and file names) RECIPES=("create-mint" "create-ata" "mint-to" "transfer-interface" "load-ata" "wrap" "unwrap") diff --git a/scripts/copy-program-snippets.sh b/scripts/copy-program-snippets.sh index d1c0790..848c48a 100644 --- a/scripts/copy-program-snippets.sh +++ b/scripts/copy-program-snippets.sh @@ -3,13 +3,13 @@ # Script to copy program code from example repos to docs snippets # Creates CodeGroup MDX files with lib.rs/instruction.rs and test.rs combined -SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/light-token" +SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/light-token" # ============================================================================= # ANCHOR PROGRAMS # ============================================================================= -ANCHOR_EXAMPLES_DIR="/home/tilo/Workspace/examples-light-token-anchor/programs/anchor/basic-instructions" +ANCHOR_EXAMPLES_DIR="/home/tilo/Workspace/examples-light-token-main/programs/anchor/basic-instructions" # Anchor recipes (output-name:anchor-dir-name) # Some have different directory names (e.g., close-token-account uses 'close' dir) @@ -82,7 +82,7 @@ done # ANCHOR MACROS # ============================================================================= -ANCHOR_MACROS_DIR="/home/tilo/Workspace/examples-light-token-anchor/programs/anchor/basic-macros" +ANCHOR_MACROS_DIR="/home/tilo/Workspace/examples-light-token-main/programs/anchor/basic-macros" ANCHOR_MACRO_RECIPES=( "create-mint:create-mint" diff --git a/scripts/copy-rust-snippets.sh b/scripts/copy-rust-snippets.sh index 4cad3dc..b73ecc4 100644 --- a/scripts/copy-rust-snippets.sh +++ b/scripts/copy-rust-snippets.sh @@ -3,8 +3,8 @@ # Script to copy Rust client code from examples-light-token-rust-client to docs snippets # Creates action.mdx and instruction.mdx files wrapped in rust code blocks -EXAMPLES_DIR="/home/tilo/Workspace/examples-light-token/rust-client" -SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/light-token" +EXAMPLES_DIR="/home/tilo/Workspace/examples-light-token-main/rust-client" +SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/light-token" # Full recipes (action + instruction in same directory) FULL_RECIPES=("create-mint" "mint-to" "transfer-interface" "transfer-checked") diff --git a/scripts/generate-llms-txt.js b/scripts/generate-llms-txt.js index 20cab20..a42bb6f 100644 --- a/scripts/generate-llms-txt.js +++ b/scripts/generate-llms-txt.js @@ -181,7 +181,7 @@ function splitLightTokenProgram(group) { for (const entry of group.pages) { if (typeof entry === 'string') { basics.push(formatPage(entry)); - } else if (entry.group === 'Cookbook' || entry.group === 'Examples') { + } else if (entry.group === 'Cookbook' || entry.group === 'Examples' || entry.group === 'Extensions') { basics.push(...collectFlatPages(entry.pages)); } else if (entry.group === 'For Stablecoin Payments') { paymentsWallets.push(...collectFlatPages(entry.pages)); @@ -248,13 +248,13 @@ function buildOpenApiSpecs() { // ── Hardcoded examples ────────────────────────────────────────────── const EXAMPLES_DEFI = [ - '- [cp-swap-reference](https://github.com/Lightprotocol/program-examples/tree/main/cp-swap-reference): Fork of Raydium AMM that creates markets without paying rent-exemption.', - '- [pinocchio-swap](https://github.com/Lightprotocol/program-examples/tree/main/pinocchio-swap): Light Token swap reference implementation.', - '- [token-swap](https://github.com/Lightprotocol/program-examples/tree/main/token-swap): AMM with liquidity pools and swaps.', - '- [escrow](https://github.com/Lightprotocol/program-examples/tree/main/escrow): Peer-to-peer light-token swap with offer/accept flow.', - '- [fundraiser](https://github.com/Lightprotocol/program-examples/tree/main/fundraiser): Token fundraiser with target, deadline, and refunds.', - '- [create-and-transfer](https://github.com/Lightprotocol/program-examples/tree/main/create-and-transfer): Create account via macro and transfer via CPI.', - '- [light-token-minter](https://github.com/Lightprotocol/program-examples/tree/main/light-token-minter): Create light-mints with metadata, mint tokens.', + '- [cp-swap-reference](https://github.com/Lightprotocol/cp-swap-reference): Fork of Raydium AMM that creates markets without paying rent-exemption.', + '- [pinocchio-swap](https://github.com/Lightprotocol/examples-light-token/tree/main/pinocchio/swap): Light Token swap reference implementation.', + '- [token-swap](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/token-swap): AMM with liquidity pools and swaps.', + '- [escrow](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/escrow): Peer-to-peer light-token swap with offer/accept flow.', + '- [fundraiser](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/fundraiser): Token fundraiser with target, deadline, and refunds.', + '- [create-and-transfer](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/create-and-transfer): Create account via macro and transfer via CPI.', + '- [light-token-minter](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/light-token-minter): Create light-mints with metadata, mint tokens.', ]; const EXAMPLES_PAYMENTS = [ @@ -262,7 +262,8 @@ const EXAMPLES_PAYMENTS = [ '- [sign-with-privy](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy): Light-token operations signed with Privy wallets.', '- [sign-with-wallet-adapter](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter): Light-token operations signed with Wallet Adapter.', '- [gasless-transactions](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions): Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees.', - '- [spl-to-light](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/spl-to-light): Transfer from SPL to Light via TransferInterface.', + '- [spl-to-light](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/instructions/spl_to_light_transfer.rs): Transfer from SPL to Light via TransferInterface.', + '- [streaming-tokens](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/streaming-tokens): Stream mint events using Laserstream.', ]; // ── Hardcoded primitives routing table ──────────────────────────────── @@ -329,13 +330,13 @@ function generate() { // Light Token sections (payments, defi, streaming, then basics) const ltGroup = docAnchor.groups.find( - (g) => g.group === 'Light Token Program', + (g) => g.group === 'Light Token APIs', ); if (ltGroup) sections.push(...splitLightTokenProgram(ltGroup)); // Remaining Documentation groups (PDA, Other Use Cases, Learn, Resources) for (const group of docAnchor.groups) { - if (group.group === 'Introduction' || group.group === 'Light Token Program') + if (group.group === 'Introduction' || group.group === 'Light Token APIs') continue; sections.push({ name: sectionRenames[group.group] || group.group, diff --git a/skill.md b/skill.md index 2727700..541783a 100644 --- a/skill.md +++ b/skill.md @@ -82,35 +82,16 @@ npx skills add Lightprotocol/skills | Use case | Skill | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| Skill for payment flows using Light Token APIs for sponsored rent-exemption. | [payments](https://github.com/Lightprotocol/skills/tree/main/skills/payments) | | For Solana program development with tokens and PDAs, Light is 200x cheaper than SPL/ Solana and has minimal code differences | [light-sdk](https://github.com/Lightprotocol/skills/tree/main/skills/light-sdk) | | For client development with tokens on Solana, Light Token is 200x cheaper than SPL and has minimal changes | [light-token-client](https://github.com/Lightprotocol/skills/tree/main/skills/light-token-client) | | For data pipelines, aggregators, or indexers, real-time account state streaming on Solana with light account hot/cold lifecycle tracking | [data-streaming](https://github.com/Lightprotocol/skills/tree/main/skills/data-streaming) | -| Skill for payment flows using Light Token APIs for sponsored rent-exemption. | [payments](https://github.com/Lightprotocol/skills/tree/main/skills/payments) | | For token distribution on Solana 5000x cheaper than SPL (rewards, airdrops, depins, ...) | [token-distribution](https://github.com/Lightprotocol/skills/tree/main/skills/token-distribution) | | For custom ZK Solana programs and privacy-preserving applications to prevent double spending | [zk-nullifier](https://github.com/Lightprotocol/skills/tree/main/skills/zk-nullifier) | | For program development on Solana with infrequently accessed state, such as per-user state, DePIN registrations, ... | [solana-compression](https://github.com/Lightprotocol/skills/tree/main/skills/solana-compression) | | For testing with Light Protocol programs and clients on localnet, devnet, and mainnet validation | [testing](https://github.com/Lightprotocol/skills/tree/main/skills/testing) | | For questions about compressed accounts, Light SDK, Solana development, Claude Code features, or agent skills | [ask-mcp](https://github.com/Lightprotocol/skills/tree/main/skills/ask-mcp) | -### Install to Claude Code - -Add the marketplace and install: - -``` -/plugin marketplace add Lightprotocol/skills -/plugin install solana-rent-free-dev -``` - -All skills are included. Use them by name (`/light-sdk`, `/token-distribution`, `/testing`, etc.) or let Claude invoke them based on task context. - -### Install to Cursor - -1. Open Settings (**Cmd+Shift+J** / **Ctrl+Shift+J**) -2. Navigate to **Rules & Commands** → **Project Rules** → **Add Rule** → **Remote Rule (GitHub)** -3. Enter: `https://github.com/Lightprotocol/skills.git` - -Skills are auto-discovered based on context. Ask about light-token, defi, payments, or program migration and the agent uses the relevant skill automatically. - ### Install to Any Agent ``` @@ -131,7 +112,7 @@ A token standard functionally equivalent to SPL that stores mint and token accou The token program pays rent-exemption cost for you. When an account has no remaining sponsored rent, the account is automatically compressed. Your tokens are cryptographically preserved as a compressed token account (rent-free). The account is loaded into hot account state in-flight when someone interacts with it again. -Use for: Launchpads, DeFi, token transfers, payments, ... . +Use for: Stablecoin Orchestration, Cards, Agent Commerce, Defi, ... . ### light-PDA @@ -169,27 +150,40 @@ Use rent-free PDAs for: user state, app state, nullifiers for payments, DePIN no - **light-token accounts hold SPL and Token-2022 balances**, not just light-mint balances. - When sponsored rent on a light-token or light-PDA runs out, the account compresses. It decompresses on next interaction. -## Examples - -### Toolkits +## Payment Flows + +| Name | Description | Docs | Examples | +|------|-------------|------|----------| +| Overview | Learn how the Light Token APIs reduce account creation cost for stablecoin payment infrastructure by 99% with similar developer experience to SPL / Token 2022. | [overview](https://zkcompression.com/light-token/payments/overview) | | +| Basic payment | Send a single token transfer with Light Token APIs for stablecoin payments with comparison to SPL. | [basic-payment](https://zkcompression.com/light-token/payments/basic-payment) | [send-action](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/send-action.ts) \| [send-instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/send-instruction.ts) | +| Batch payments | Send payments to multiple recipients in a single transaction or sequentially. | [batch-payments](https://zkcompression.com/light-token/payments/batch-payments) | [batch-send](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/batch-send.ts) | +| Payment with memo | Attach invoice IDs, payment references, or notes to Light Token transfers using Solana's memo program. The memo is recorded in the transaction logs for reconciliation. | [payment-with-memo](https://zkcompression.com/light-token/payments/payment-with-memo) | [payment-with-memo](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/send/payment-with-memo.ts) | +| Receive payments | Prepare to receive token payments by loading cold accounts and sharing your associated token account address. | [receive-payments](https://zkcompression.com/light-token/payments/receive-payments) | [receive](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/receive/receive.ts) | +| Verify payments | Query token balances and transaction history to verify incoming payments. | [verify-payments](https://zkcompression.com/light-token/payments/verify-payments) | [get-balance](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-balance.ts) \| [get-history](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-history.ts) | +| Verify address | Verify recipient addresses before sending payments. Address validation prevents sending tokens to invalid or unexpected account types. | [verify-recipient-address](https://zkcompression.com/light-token/payments/verify-recipient-address) | [verify-address](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/verify-address.ts) | +| Wrap and unwrap | Move tokens between SPL / Token 2022 and Light Token accounts for interoperability with applications that don't support Light Token yet. | [wrap-unwrap](https://zkcompression.com/light-token/payments/wrap-unwrap) | [wrap](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/wrap.ts) \| [unwrap](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/interop/unwrap.ts) | +| Spend permissions | Delegate token spending to a third party with an amount cap. The delegate can transfer tokens on behalf of the owner up to the approved amount, without the owner signing each transaction. | [spend-permissions](https://zkcompression.com/light-token/payments/spend-permissions) | [delegate-full-flow](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/spend-permissions/delegate-full-flow.ts) | +| Nullifier PDAs | Create rent-free nullifier PDAs to prevent duplicate actions. | [nullifier-pda](https://zkcompression.com/pda/compressed-pdas/nullifier-pda) | | +| Production readiness | Non-exhaustive checklist for deploying Light Token payment flows to production, including RPC infrastructure, error handling, and security. | [production-readiness](https://zkcompression.com/light-token/payments/production-readiness) | | +| Wallet integration | Guide for Wallet Applications to add Light-token support. | [wallets/overview](https://zkcompression.com/light-token/wallets/overview) | | +| Sign with Privy | Integrate light-token with Privy embedded wallets for rent-free token accounts and transfers. | [privy](https://zkcompression.com/light-token/wallets/privy) | [sign-with-privy](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy) | +| Sign with Wallet Adapter | Integrate light-token with Solana Wallet Adapter for rent-free token accounts and transfers. | [wallet-adapter](https://zkcompression.com/light-token/wallets/wallet-adapter) | [sign-with-wallet-adapter](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter) | +| Gasless transactions | Abstract SOL fees so users never hold SOL. Sponsor top-ups and transaction fees by setting your application as the fee payer. | [gasless-transactions](https://zkcompression.com/light-token/wallets/gasless-transactions) | [gasless-transactions](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions) | +| Smart wallets | Send Light Tokens from PDA-based smart wallets. Covers off-curve associated token account creation, instruction-level transfers, and sync and async execution with Squads. | [smart-wallets](https://zkcompression.com/light-token/wallets/smart-wallets) | | -| | Description | -|---------|-------------| -| [Payments](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/payments) | All you need for wallet integrations and payment flows. Minimal API differences to SPL. | -| [Streaming Tokens](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/streaming-tokens/) | Stream mint events using Laserstream | -| [Sign with Privy](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy/) | Light-token operations signed with Privy wallets (Node.js + React) | -| [Gasless Transactions](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions/) | Abstract SOL fees so users never hold SOL. Sponsor rent top-ups and transaction fees. | +## Examples ### TypeScript client (`@lightprotocol/compressed-token`) | Operation | Docs guide | GitHub example | | --------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `createMintInterface` | [create-mint](https://zkcompression.com/light-token/cookbook/create-mint) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-mint.ts) | +| `createMintInterface` | [create-mint](https://zkcompression.com/light-token/cookbook/create-mint) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-mint.ts) \| [instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/create-mint.ts) | | `createAtaInterface` | [create-ata](https://zkcompression.com/light-token/cookbook/create-ata) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-ata.ts) \| [instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/create-ata.ts) | | `mintToInterface` | [mint-to](https://zkcompression.com/light-token/cookbook/mint-to) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/mint-to.ts) \| [instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/mint-to.ts) | | `transferInterface` | [transfer-interface](https://zkcompression.com/light-token/cookbook/transfer-interface) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/transfer-interface.ts) \| [instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/transfer-interface.ts) | | `approve` | [approve-revoke](https://zkcompression.com/light-token/cookbook/approve-revoke) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-approve.ts) | | `revoke` | [approve-revoke](https://zkcompression.com/light-token/cookbook/approve-revoke) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-revoke.ts) | +| `delegateTransfer` | [transfer-delegated](https://zkcompression.com/light-token/cookbook/transfer-delegated) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-transfer.ts) | | `wrap` | [wrap-unwrap](https://zkcompression.com/light-token/cookbook/wrap-unwrap) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/wrap.ts) \| [instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/wrap.ts) | | `unwrap` | [wrap-unwrap](https://zkcompression.com/light-token/cookbook/wrap-unwrap) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/unwrap.ts) \| [instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/unwrap.ts) | | `loadAta` | [load-ata](https://zkcompression.com/light-token/cookbook/load-ata) | [action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/load-ata.ts) \| [instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/load-ata.ts) | @@ -240,7 +234,7 @@ Use rent-free PDAs for: user state, app state, nullifiers for payments, DePIN no | | Description | | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | | [counter](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/counter) | Create PDA with sponsored rent-exemption | -| [create-ata](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/create-ata) | Create associated light-token account | +| [create-ata](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/create-associated-token-account) | Create associated light-token account | | [create-mint](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/create-mint) | Create light-token mint | | [create-token-account](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/create-token-account) | Create light-token account | @@ -250,7 +244,7 @@ CPI calls can be combined with existing and/or light macros. The API is a supers | Operation | Docs guide | GitHub example | | ---------------------------- | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `CreateAssociatedAccountCpi` | [create-ata](https://zkcompression.com/light-token/cookbook/create-ata) | [src](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/create-ata/src/lib.rs) | +| `CreateAssociatedAccountCpi` | [create-ata](https://zkcompression.com/light-token/cookbook/create-ata) | [src](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/create-associated-token-account/src/lib.rs) | | `CreateTokenAccountCpi` | [create-token-account](https://zkcompression.com/light-token/cookbook/create-token-account) | [src](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/create-token-account/src/lib.rs) | | `CreateMintCpi` | [create-mint](https://zkcompression.com/light-token/cookbook/create-mint) | [src](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/create-mint/src/lib.rs) | | `MintToCpi` | [mint-to](https://zkcompression.com/light-token/cookbook/mint-to) | [src](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/mint-to/src/lib.rs) | @@ -264,6 +258,21 @@ CPI calls can be combined with existing and/or light macros. The API is a supers | `ThawCpi` | [freeze-thaw](https://zkcompression.com/light-token/cookbook/freeze-thaw) | [src](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/thaw/src/lib.rs) | | `CloseAccountCpi` | [close-token-account](https://zkcompression.com/light-token/cookbook/close-token-account) | [src](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/close/src/lib.rs) | +### Extensions + +| Extension | Docs guide | GitHub example | +|-----------|-----------|----------------| +| Close mint | [close-mint](https://zkcompression.com/light-token/extensions/close-mint) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/close-mint.ts) | +| Confidential transfer | [confidential-transfer](https://zkcompression.com/light-token/extensions/confidential-transfer) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/confidential-transfer.ts) | +| Default account state | [default-account-state](https://zkcompression.com/light-token/extensions/default-account-state) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/default-account-state.ts) | +| Interest-bearing tokens | [interest-bearing-tokens](https://zkcompression.com/light-token/extensions/interest-bearing-tokens) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/interest-bearing-tokens.ts) | +| Metadata and metadata pointer | [metadata-and-metadata-pointer](https://zkcompression.com/light-token/extensions/metadata-and-metadata-pointer) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/metadata-and-metadata-pointer.ts) | +| Pausable mint | [pausable-mint](https://zkcompression.com/light-token/extensions/pausable-mint) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/pausable-mint.ts) | +| Permanent delegate | [permanent-delegate](https://zkcompression.com/light-token/extensions/permanent-delegate) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/permanent-delegate.ts) | +| Token groups and members | [token-groups-and-members](https://zkcompression.com/light-token/extensions/token-groups-and-members) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts) | +| Transfer fees | [transfer-fees](https://zkcompression.com/light-token/extensions/transfer-fees) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-fees.ts) | +| Transfer hook | [transfer-hook](https://zkcompression.com/light-token/extensions/transfer-hook) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-hook.ts) | + ## SDK references ### TypeScript packages diff --git a/snippets/ai-prompts/all-prompts.mdx b/snippets/ai-prompts/all-prompts.mdx index 3363817..b0e7254 100644 --- a/snippets/ai-prompts/all-prompts.mdx +++ b/snippets/ai-prompts/all-prompts.mdx @@ -31,13 +31,60 @@ import WalletAdapter from "/snippets/ai-prompts/wallets/wallet-adapter.mdx"; import Privy from "/snippets/ai-prompts/wallets/privy.mdx"; import GaslessTransactions from "/snippets/ai-prompts/wallets/gasless-transactions.mdx"; +{/* extensions */} +import ExtCloseMint from "/snippets/ai-prompts/extensions/close-mint.mdx"; +import ExtConfidentialTransfer from "/snippets/ai-prompts/extensions/confidential-transfer.mdx"; +import ExtDefaultAccountState from "/snippets/ai-prompts/extensions/default-account-state.mdx"; +import ExtInterestBearing from "/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx"; +import ExtMetadataPointer from "/snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx"; +import ExtPausableMint from "/snippets/ai-prompts/extensions/pausable-mint.mdx"; +import ExtPermanentDelegate from "/snippets/ai-prompts/extensions/permanent-delegate.mdx"; +import ExtTokenGroups from "/snippets/ai-prompts/extensions/token-groups-and-members.mdx"; +import ExtTransferFees from "/snippets/ai-prompts/extensions/transfer-fees.mdx"; +import ExtTransferHook from "/snippets/ai-prompts/extensions/transfer-hook.mdx"; + {/* migration */} import V1ToV2Migration from "/snippets/ai-prompts/v1-to-v2-migration.mdx"; + +## Stablecoin Payments + + +Copy the prompt below or view the [guide](/light-token/payments/integration-guide). + + + + +Copy the prompt below or view the [guide](/light-token/wallets/wallet-adapter). + + + + +Copy the prompt below or view the [guide](/light-token/wallets/privy). + + + + +Copy the prompt below or view the [guide](/light-token/wallets/gasless-transactions). + + + + +Copy the prompt below or view the [guide](/pda/compressed-pdas/how-to-create-nullifier-pdas). + + + ## Light Token Recipes +## Token Distribution + + +Copy the prompt below or view the [guide](/token-distribution). + + + ## DeFi @@ -67,40 +114,6 @@ Copy the prompt below or view the [guide](/light-token/streaming/tokens). -## Stablecoin Payments - - -Copy the prompt below or view the [guide](/light-token/payments/integration-guide). - - - - -Copy the prompt below or view the [guide](/pda/compressed-pdas/how-to-create-nullifier-pdas). - - - -## Wallets - - -Copy the prompt below or view the [guide](/light-token/wallets/overview). - - - - -Copy the prompt below or view the [guide](/light-token/wallets/wallet-adapter). - - - - -Copy the prompt below or view the [guide](/light-token/wallets/privy). - - - - -Copy the prompt below or view the [guide](/light-token/wallets/gasless-transactions). - - - ## Light-PDA @@ -145,9 +158,54 @@ Copy the prompt below or view the [guide](/resources/migration-v1-to-v2). -## Token Distribution +## Extensions - -Copy the prompt below or view the [guide](/token-distribution). - + +Copy the prompt below or view the [guide](/light-token/extensions/close-mint). + + + + +Copy the prompt below or view the [guide](/light-token/extensions/confidential-transfer). + + + +Copy the prompt below or view the [guide](/light-token/extensions/default-account-state). + + + + +Copy the prompt below or view the [guide](/light-token/extensions/interest-bearing-tokens). + + + + +Copy the prompt below or view the [guide](/light-token/extensions/metadata-and-metadata-pointer). + + + + +Copy the prompt below or view the [guide](/light-token/extensions/pausable-mint). + + + + +Copy the prompt below or view the [guide](/light-token/extensions/permanent-delegate). + + + + +Copy the prompt below or view the [guide](/light-token/extensions/token-groups-and-members). + + + + +Copy the prompt below or view the [guide](/light-token/extensions/transfer-fees). + + + + +Copy the prompt below or view the [guide](/light-token/extensions/transfer-hook). + + \ No newline at end of file diff --git a/snippets/ai-prompts/wallets/privy.mdx b/snippets/ai-prompts/wallets/privy.mdx index 1e81f3b..192e875 100644 --- a/snippets/ai-prompts/wallets/privy.mdx +++ b/snippets/ai-prompts/wallets/privy.mdx @@ -12,8 +12,8 @@ Context: - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison - Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js -- Node.js example: https://github.com/Lightprotocol/examples-light-token/tree/main/privy/nodejs -- React example: https://github.com/Lightprotocol/examples-light-token/tree/main/privy/react +- Node.js example: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy/nodejs +- React example: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy/react SPL → Light Token API mapping: | Operation | SPL | Light Token | @@ -83,8 +83,8 @@ Context: - SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison - Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments - Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js -- Node.js example: https://github.com/Lightprotocol/examples-light-token/tree/main/privy/nodejs -- React example: https://github.com/Lightprotocol/examples-light-token/tree/main/privy/react +- Node.js example: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy/nodejs +- React example: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy/react SPL → Light Token API mapping: | Operation | SPL | Light Token | diff --git a/snippets/code-snippets/light-token/approve-revoke/rust-client/approve-instruction.mdx b/snippets/code-snippets/light-token/approve-revoke/rust-client/approve-instruction.mdx index 3a60f85..d8a5c27 100644 --- a/snippets/code-snippets/light-token/approve-revoke/rust-client/approve-instruction.mdx +++ b/snippets/code-snippets/light-token/approve-revoke/rust-client/approve-instruction.mdx @@ -23,6 +23,7 @@ async fn main() -> Result<(), Box> { delegate: delegate.pubkey(), owner: payer.pubkey(), amount: delegate_amount, + fee_payer: payer.pubkey(), } .instruction()?; diff --git a/snippets/code-snippets/light-token/approve-revoke/rust-client/revoke-instruction.mdx b/snippets/code-snippets/light-token/approve-revoke/rust-client/revoke-instruction.mdx index d18bc44..8aabf3e 100644 --- a/snippets/code-snippets/light-token/approve-revoke/rust-client/revoke-instruction.mdx +++ b/snippets/code-snippets/light-token/approve-revoke/rust-client/revoke-instruction.mdx @@ -18,6 +18,7 @@ async fn main() -> Result<(), Box> { let revoke_instruction = Revoke { token_account: associated_token_account, owner: payer.pubkey(), + fee_payer: payer.pubkey(), } .instruction()?; diff --git a/snippets/code-snippets/light-token/burn/rust-client/instruction.mdx b/snippets/code-snippets/light-token/burn/rust-client/instruction.mdx index a43ab64..68a7c58 100644 --- a/snippets/code-snippets/light-token/burn/rust-client/instruction.mdx +++ b/snippets/code-snippets/light-token/burn/rust-client/instruction.mdx @@ -23,8 +23,7 @@ async fn main() -> Result<(), Box> { mint, amount: burn_amount, authority: payer.pubkey(), - max_top_up: None, - fee_payer: None, + fee_payer: payer.pubkey(), } .instruction()?; diff --git a/snippets/code-snippets/light-token/create-mint/rust-client/instruction.mdx b/snippets/code-snippets/light-token/create-mint/rust-client/instruction.mdx index f56e088..bce376d 100644 --- a/snippets/code-snippets/light-token/create-mint/rust-client/instruction.mdx +++ b/snippets/code-snippets/light-token/create-mint/rust-client/instruction.mdx @@ -18,7 +18,7 @@ use solana_sdk::{signature::Keypair, signer::Signer}; #[tokio::main] async fn main() -> Result<(), Box> { - let mut rpc = LightProgramTest::new(ProgramTestConfig::new_v2(false, None)).await?; + let mut rpc = LightProgramTest::new(ProgramTestConfig::new(false, None)).await?; let payer = rpc.get_payer().insecure_clone(); let mint_seed = Keypair::new(); diff --git a/snippets/code-snippets/light-token/mint-to/rust-client/instruction.mdx b/snippets/code-snippets/light-token/mint-to/rust-client/instruction.mdx index cd9f6d9..c3ddcf2 100644 --- a/snippets/code-snippets/light-token/mint-to/rust-client/instruction.mdx +++ b/snippets/code-snippets/light-token/mint-to/rust-client/instruction.mdx @@ -23,8 +23,7 @@ async fn main() -> Result<(), Box> { destination: associated_token_account, amount: mint_amount, authority: payer.pubkey(), - max_top_up: None, - fee_payer: None, + fee_payer: payer.pubkey(), } .instruction()?; diff --git a/snippets/code-snippets/light-token/transfer-interface/rust-client/instruction.mdx b/snippets/code-snippets/light-token/transfer-interface/rust-client/instruction.mdx index bc4ebd4..afce1ac 100644 --- a/snippets/code-snippets/light-token/transfer-interface/rust-client/instruction.mdx +++ b/snippets/code-snippets/light-token/transfer-interface/rust-client/instruction.mdx @@ -15,7 +15,7 @@ use solana_sdk::signer::Signer; #[tokio::main] async fn main() -> Result<(), Box> { - let mut rpc = LightProgramTest::new(ProgramTestConfig::new_v2(true, None)).await?; + let mut rpc = LightProgramTest::new(ProgramTestConfig::new(true, None)).await?; let payer = rpc.get_payer().insecure_clone(); let decimals = 2u8; @@ -51,8 +51,8 @@ async fn main() -> Result<(), Box> { decimals, authority: payer.pubkey(), payer: payer.pubkey(), + mint, spl_interface: Some(spl_interface), - max_top_up: None, source_owner: spl_token::ID, destination_owner: LIGHT_TOKEN_PROGRAM_ID, } diff --git a/snippets/code-snippets/payments/receive/receive.mdx b/snippets/code-snippets/payments/receive/receive.mdx index 3501d75..0a44a95 100644 --- a/snippets/code-snippets/payments/receive/receive.mdx +++ b/snippets/code-snippets/payments/receive/receive.mdx @@ -4,12 +4,11 @@ import { Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; -import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; import { getAssociatedTokenAddressInterface, - transferInterface, createLoadAtaInstructions, -} from "@lightprotocol/compressed-token/unified"; +} from "@lightprotocol/compressed-token"; +import { transferInterface } from "@lightprotocol/compressed-token/unified"; import { rpc, payer, setup } from "../setup.js"; (async function () { @@ -17,22 +16,22 @@ import { rpc, payer, setup } from "../setup.js"; // Transfer to a fresh recipient so they have cold tokens const recipient = Keypair.generate(); - await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); - const recipientAta = getAssociatedTokenAddressInterface( - mint, - recipient.publicKey - ); await transferInterface( rpc, payer, senderAta, mint, - recipientAta, + recipient.publicKey, payer, 500 ); // --- Receive: load creates ATA if needed + pulls cold state to hot --- + const recipientAta = getAssociatedTokenAddressInterface( + mint, + recipient.publicKey + ); + // Returns TransactionInstruction[][]. Each inner array is one txn. // Almost always one. Empty = noop. const instructions = await createLoadAtaInstructions( diff --git a/snippets/code-snippets/payments/send/batch-send.mdx b/snippets/code-snippets/payments/send/batch-send.mdx index 50e5e18..b51bfcc 100644 --- a/snippets/code-snippets/payments/send/batch-send.mdx +++ b/snippets/code-snippets/payments/send/batch-send.mdx @@ -9,7 +9,10 @@ import { getAssociatedTokenAddressInterface, getAtaInterface, } from "@lightprotocol/compressed-token"; -import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; +import { + createTransferToAccountInterfaceInstructions, + createLoadAtaInstructions, +} from "@lightprotocol/compressed-token/unified"; import { rpc, payer, setup } from "../setup.js"; (async function () { @@ -33,7 +36,7 @@ import { rpc, payer, setup } from "../setup.js"; getAssociatedTokenAddressInterface(mint, address) ); - // Step 4: Create transfer instructions + // Step 4: Create transfer instructions using explicit-account variant const COMPUTE_BUDGET_ID = "ComputeBudget111111111111111111111111111111"; const allTransferIxs = []; @@ -41,7 +44,7 @@ import { rpc, payer, setup } from "../setup.js"; for (const { address, amount } of recipients) { const destination = getAssociatedTokenAddressInterface(mint, address); - const ixs = await createTransferInterfaceInstructions( + const ixs = await createTransferToAccountInterfaceInstructions( rpc, payer.publicKey, mint, diff --git a/snippets/code-snippets/payments/send/payment-with-memo.mdx b/snippets/code-snippets/payments/send/payment-with-memo.mdx index 9a536c8..1736530 100644 --- a/snippets/code-snippets/payments/send/payment-with-memo.mdx +++ b/snippets/code-snippets/payments/send/payment-with-memo.mdx @@ -6,9 +6,7 @@ import { PublicKey, sendAndConfirmTransaction, } from "@solana/web3.js"; -import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; import { - getAssociatedTokenAddressInterface, createTransferInterfaceInstructions, sliceLast, } from "@lightprotocol/compressed-token/unified"; @@ -20,13 +18,7 @@ const MEMO_PROGRAM_ID = new PublicKey( (async function () { const { mint } = await setup(); - const recipient = Keypair.generate(); - await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); - const destination = getAssociatedTokenAddressInterface( - mint, - recipient.publicKey - ); const instructions = await createTransferInterfaceInstructions( rpc, @@ -34,7 +26,7 @@ const MEMO_PROGRAM_ID = new PublicKey( mint, 100, payer.publicKey, - destination + recipient.publicKey ); const { rest: loadInstructions, last: transferInstructions } = diff --git a/snippets/code-snippets/payments/send/send-action.mdx b/snippets/code-snippets/payments/send/send-action.mdx index cea53f6..4777ad0 100644 --- a/snippets/code-snippets/payments/send/send-action.mdx +++ b/snippets/code-snippets/payments/send/send-action.mdx @@ -1,28 +1,18 @@ ```typescript import { Keypair } from "@solana/web3.js"; -import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; -import { - getAssociatedTokenAddressInterface, - transferInterface, -} from "@lightprotocol/compressed-token/unified"; +import { transferInterface } from "@lightprotocol/compressed-token/unified"; import { rpc, payer, setup } from "../setup.js"; (async function () { const { mint, senderAta } = await setup(); - const recipient = Keypair.generate(); - await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); - const recipientAta = getAssociatedTokenAddressInterface( - mint, - recipient.publicKey - ); const sig = await transferInterface( rpc, payer, senderAta, mint, - recipientAta, + recipient.publicKey, payer, 100 ); diff --git a/snippets/code-snippets/payments/send/send-instruction.mdx b/snippets/code-snippets/payments/send/send-instruction.mdx index 5991ac0..619bf93 100644 --- a/snippets/code-snippets/payments/send/send-instruction.mdx +++ b/snippets/code-snippets/payments/send/send-instruction.mdx @@ -4,22 +4,12 @@ import { Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; -import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; -import { - getAssociatedTokenAddressInterface, - createTransferInterfaceInstructions, -} from "@lightprotocol/compressed-token/unified"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; import { rpc, payer, setup } from "../setup.js"; (async function () { const { mint } = await setup(); - const recipient = Keypair.generate(); - await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); - const destination = getAssociatedTokenAddressInterface( - mint, - recipient.publicKey - ); // Returns TransactionInstruction[][]. Each inner array is one txn. const instructions = await createTransferInterfaceInstructions( @@ -28,7 +18,7 @@ import { rpc, payer, setup } from "../setup.js"; mint, 100, payer.publicKey, - destination + recipient.publicKey ); for (const ixs of instructions) { diff --git a/snippets/code-snippets/payments/send/sign-all-transactions.mdx b/snippets/code-snippets/payments/send/sign-all-transactions.mdx index 80f13f8..3c551f8 100644 --- a/snippets/code-snippets/payments/send/sign-all-transactions.mdx +++ b/snippets/code-snippets/payments/send/sign-all-transactions.mdx @@ -4,9 +4,7 @@ import { Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; -import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; import { - getAssociatedTokenAddressInterface, createTransferInterfaceInstructions, sliceLast, } from "@lightprotocol/compressed-token/unified"; @@ -14,13 +12,7 @@ import { rpc, payer, setup } from "../setup.js"; (async function () { const { mint } = await setup(); - const recipient = Keypair.generate(); - await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); - const destination = getAssociatedTokenAddressInterface( - mint, - recipient.publicKey - ); const instructions = await createTransferInterfaceInstructions( rpc, @@ -28,7 +20,7 @@ import { rpc, payer, setup } from "../setup.js"; mint, 100, payer.publicKey, - destination + recipient.publicKey ); // --- Sign all transactions together — one approval for all --- @@ -48,7 +40,7 @@ import { rpc, payer, setup } from "../setup.js"; mint, 50, payer.publicKey, - destination + recipient.publicKey ); const { rest: loadInstructions, last: transferInstructions } = diff --git a/snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx b/snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx index 2107b99..18499f3 100644 --- a/snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx +++ b/snippets/code-snippets/payments/spend-permissions/delegate-full-flow.mdx @@ -3,7 +3,6 @@ import { Keypair } from "@solana/web3.js"; import { getAtaInterface } from "@lightprotocol/compressed-token"; import { approveInterface, - transferDelegatedInterface, revokeInterface, } from "@lightprotocol/compressed-token/unified"; import { rpc, payer, setup } from "../setup.js"; @@ -44,48 +43,19 @@ import { rpc, payer, setup } from "../setup.js"; ); console.log(" Account balance:", account.parsed.amount.toString()); - // 3. Delegate transfers 200,000 tokens on behalf of owner - const recipient = Keypair.generate(); - const transferTx = await transferDelegatedInterface( - rpc, - payer, - senderAta, - mint, - recipient.publicKey, - delegate, - payer.publicKey, - 200_000 - ); - console.log("\n3. Delegate transferred 200,000 tokens"); - console.log(" Tx:", transferTx); - - // 4. Verify balances after delegated transfer - const afterTransfer = await getAtaInterface( - rpc, - senderAta, - payer.publicKey, - mint - ); - console.log("\n4. Account status after delegated transfer:"); - console.log( - " Remaining allowance:", - afterTransfer.parsed.delegatedAmount.toString() - ); - console.log(" Account balance:", afterTransfer.parsed.amount.toString()); - - // 5. Owner revokes all delegate permissions + // 3. Owner revokes all delegate permissions const revokeTx = await revokeInterface(rpc, payer, senderAta, mint, payer); - console.log("\n5. Revoked all delegate permissions"); + console.log("\n3. Revoked all delegate permissions"); console.log(" Tx:", revokeTx); - // 6. Verify delegate is removed + // 4. Verify delegate is removed const afterRevoke = await getAtaInterface( rpc, senderAta, payer.publicKey, mint ); - console.log("\n6. Account status after revoke:"); + console.log("\n4. Account status after revoke:"); console.log( " Delegate:", afterRevoke.parsed.delegate?.toBase58() ?? "none" diff --git a/snippets/code-snippets/payments/verify/get-balance.mdx b/snippets/code-snippets/payments/verify/get-balance.mdx index 7192a57..a161ce8 100644 --- a/snippets/code-snippets/payments/verify/get-balance.mdx +++ b/snippets/code-snippets/payments/verify/get-balance.mdx @@ -1,35 +1,31 @@ ```typescript import { Keypair } from "@solana/web3.js"; import { - createAtaInterfaceIdempotent, + getAssociatedTokenAddressInterface, getAtaInterface, } from "@lightprotocol/compressed-token"; -import { - getAssociatedTokenAddressInterface, - transferInterface, -} from "@lightprotocol/compressed-token/unified"; +import { transferInterface } from "@lightprotocol/compressed-token/unified"; import { rpc, payer, setup } from "../setup.js"; (async function () { const { mint, senderAta } = await setup(); const recipient = Keypair.generate(); - await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); - const recipientAta = getAssociatedTokenAddressInterface( - mint, - recipient.publicKey - ); await transferInterface( rpc, payer, senderAta, mint, - recipientAta, + recipient.publicKey, payer, 100 ); // Get recipient's balance + const recipientAta = getAssociatedTokenAddressInterface( + mint, + recipient.publicKey + ); const { parsed: account } = await getAtaInterface( rpc, recipientAta, diff --git a/snippets/code-snippets/payments/verify/get-history.mdx b/snippets/code-snippets/payments/verify/get-history.mdx index 2d8398a..e41e1c9 100644 --- a/snippets/code-snippets/payments/verify/get-history.mdx +++ b/snippets/code-snippets/payments/verify/get-history.mdx @@ -1,27 +1,18 @@ ```typescript import { Keypair } from "@solana/web3.js"; -import { createAtaInterfaceIdempotent } from "@lightprotocol/compressed-token"; -import { - getAssociatedTokenAddressInterface, - transferInterface, -} from "@lightprotocol/compressed-token/unified"; +import { transferInterface } from "@lightprotocol/compressed-token/unified"; import { rpc, payer, setup } from "../setup.js"; (async function () { const { mint, senderAta } = await setup(); const recipient = Keypair.generate(); - await createAtaInterfaceIdempotent(rpc, payer, mint, recipient.publicKey); - const recipientAta = getAssociatedTokenAddressInterface( - mint, - recipient.publicKey - ); await transferInterface( rpc, payer, senderAta, mint, - recipientAta, + recipient.publicKey, payer, 100 ); diff --git a/snippets/code-snippets/privy/balances/nodejs.mdx b/snippets/code-snippets/privy/balances/nodejs.mdx index a2ca8cf..929a0b9 100644 --- a/snippets/code-snippets/privy/balances/nodejs.mdx +++ b/snippets/code-snippets/privy/balances/nodejs.mdx @@ -1,7 +1,7 @@ ```typescript import 'dotenv/config'; import {PublicKey, LAMPORTS_PER_SOL} from '@solana/web3.js'; -import {TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID} from '@solana/spl-token'; +import {TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, getMint} from '@solana/spl-token'; import {createRpc} from '@lightprotocol/stateless.js'; import { getAtaInterface, @@ -37,13 +37,13 @@ export async function getBalances( console.error('Failed to fetch SOL balance:', e); } - // Per-mint accumulator - const mintMap = new Map(); + // Per-mint accumulator (raw values, converted at assembly) + const mintMap = new Map(); const getOrCreate = (mintStr: string) => { let entry = mintMap.get(mintStr); if (!entry) { - entry = {spl: 0, t22: 0, hot: 0, cold: 0, decimals: 9}; + entry = {spl: 0n, t22: 0n, hot: 0n, cold: 0n, decimals: 9, tokenProgram: TOKEN_PROGRAM_ID}; mintMap.set(mintStr, entry); } return entry; @@ -60,7 +60,7 @@ export async function getBalances( const mint = new PublicKey(buf.subarray(0, 32)); const amount = buf.readBigUInt64LE(64); const mintStr = mint.toBase58(); - getOrCreate(mintStr).spl += toUiAmount(amount, 9); + getOrCreate(mintStr).spl += amount; } } catch { // No SPL accounts @@ -77,49 +77,66 @@ export async function getBalances( const mint = new PublicKey(buf.subarray(0, 32)); const amount = buf.readBigUInt64LE(64); const mintStr = mint.toBase58(); - getOrCreate(mintStr).t22 += toUiAmount(amount, 9); + const entry = getOrCreate(mintStr); + entry.t22 += amount; + entry.tokenProgram = TOKEN_2022_PROGRAM_ID; } } catch { // No Token 2022 accounts } - // 3. Hot balance from Light Token associated token account + // 3. Cold balance from compressed token accounts + try { + const compressed = await rpc.getCompressedTokenBalancesByOwnerV2(owner); + for (const item of compressed.value.items) { + const mintStr = item.mint.toBase58(); + getOrCreate(mintStr).cold += BigInt(item.balance.toString()); + } + } catch { + // No compressed accounts + } + + // 4. Fetch actual decimals for each mint const mintKeys = [...mintMap.keys()]; + await Promise.allSettled( + mintKeys.map(async (mintStr) => { + try { + const mint = new PublicKey(mintStr); + const entry = getOrCreate(mintStr); + const mintInfo = await getMint(rpc, mint, undefined, entry.tokenProgram); + entry.decimals = mintInfo.decimals; + } catch { + // Keep default decimals if mint fetch fails + } + }), + ); + + // 5. Hot balance from Light Token associated token account await Promise.allSettled( mintKeys.map(async (mintStr) => { try { const mint = new PublicKey(mintStr); const ata = getAssociatedTokenAddressInterface(mint, owner); const {parsed} = await getAtaInterface(rpc, ata, owner, mint); - getOrCreate(mintStr).hot = toUiAmount(parsed.amount, 9); + getOrCreate(mintStr).hot = BigInt(parsed.amount.toString()); } catch { // Associated token account does not exist for this mint } }), ); - // 4. Cold balance from compressed token accounts - try { - const compressed = await rpc.getCompressedTokenBalancesByOwnerV2(owner); - for (const item of compressed.value.items) { - const mintStr = item.mint.toBase58(); - getOrCreate(mintStr).cold += toUiAmount(BigInt(item.balance.toString()), 9); - } - } catch { - // No compressed accounts - } - - // Assemble result + // 6. Assemble result (convert raw → UI amounts here) const tokens: TokenBalance[] = []; for (const [mintStr, entry] of mintMap) { + const d = entry.decimals; tokens.push({ mint: mintStr, - decimals: entry.decimals, - hot: entry.hot, - cold: entry.cold, - spl: entry.spl, - t22: entry.t22, - unified: entry.hot + entry.cold, + decimals: d, + hot: toUiAmount(entry.hot, d), + cold: toUiAmount(entry.cold, d), + spl: toUiAmount(entry.spl, d), + t22: toUiAmount(entry.t22, d), + unified: toUiAmount(entry.hot + entry.cold, d), }); } @@ -132,9 +149,8 @@ function toBuffer(data: Buffer | Uint8Array | string | unknown): Buffer | null { return null; } -function toUiAmount(raw: bigint | {toNumber: () => number}, decimals: number): number { - const value = typeof raw === 'bigint' ? Number(raw) : raw.toNumber(); - return value / 10 ** decimals; +function toUiAmount(raw: bigint, decimals: number): number { + return Number(raw) / 10 ** decimals; } export default getBalances; diff --git a/snippets/code-snippets/privy/balances/react.mdx b/snippets/code-snippets/privy/balances/react.mdx index d4112fa..0c9f60e 100644 --- a/snippets/code-snippets/privy/balances/react.mdx +++ b/snippets/code-snippets/privy/balances/react.mdx @@ -1,7 +1,7 @@ ```typescript import { useState, useCallback } from 'react'; -import { PublicKey } from '@solana/web3.js'; -import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token'; +import { PublicKey, LAMPORTS_PER_SOL } from '@solana/web3.js'; +import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, getMint } from '@solana/spl-token'; import { createRpc } from '@lightprotocol/stateless.js'; import { getAssociatedTokenAddressInterface, @@ -32,12 +32,12 @@ export function useUnifiedBalance() { const owner = new PublicKey(ownerAddress); // Per-mint accumulator - const mintMap = new Map(); + const mintMap = new Map(); const getOrCreate = (mintStr: string) => { let entry = mintMap.get(mintStr); if (!entry) { - entry = { spl: 0n, t22: 0n, hot: 0n, cold: 0n, decimals: 9 }; + entry = { spl: 0n, t22: 0n, hot: 0n, cold: 0n, decimals: 9, tokenProgram: TOKEN_PROGRAM_ID }; mintMap.set(mintStr, entry); } return entry; @@ -79,7 +79,9 @@ export function useUnifiedBalance() { const mint = new PublicKey(buf.subarray(0, 32)); const amount = buf.readBigUInt64LE(64); const mintStr = mint.toBase58(); - getOrCreate(mintStr).t22 += amount; + const entry = getOrCreate(mintStr); + entry.t22 += amount; + entry.tokenProgram = TOKEN_2022_PROGRAM_ID; } } catch { // No Token 2022 accounts @@ -96,8 +98,22 @@ export function useUnifiedBalance() { // No compressed accounts } - // 5. Hot balance from Light Token associated token account + // 5. Fetch actual decimals for each mint const mintKeys = [...mintMap.keys()]; + await Promise.allSettled( + mintKeys.map(async (mintStr) => { + try { + const mint = new PublicKey(mintStr); + const entry = getOrCreate(mintStr); + const mintInfo = await getMint(rpc, mint, undefined, entry.tokenProgram); + entry.decimals = mintInfo.decimals; + } catch { + // Keep default decimals if mint fetch fails + } + }), + ); + + // 6. Hot balance from Light Token associated token account await Promise.allSettled( mintKeys.map(async (mintStr) => { try { @@ -112,7 +128,7 @@ export function useUnifiedBalance() { }), ); - // 6. Assemble TokenBalance[] + // 7. Assemble TokenBalance[] const result: TokenBalance[] = []; // SOL entry diff --git a/snippets/code-snippets/privy/receive/nodejs.mdx b/snippets/code-snippets/privy/receive/nodejs.mdx index 4cfeb47..9e21246 100644 --- a/snippets/code-snippets/privy/receive/nodejs.mdx +++ b/snippets/code-snippets/privy/receive/nodejs.mdx @@ -1,63 +1,2 @@ ```typescript -import 'dotenv/config'; -import {PrivyClient} from '@privy-io/node'; -import {createRpc} from '@lightprotocol/stateless.js'; -import {PublicKey, Transaction} from '@solana/web3.js'; -import { - createLoadAtaInstructions, - getAssociatedTokenAddressInterface, -} from '@lightprotocol/compressed-token/unified'; - -const receiveLightTokens = async ( - recipientAddress: string, - tokenMintAddress: string, -) => { - const connection = createRpc(process.env.HELIUS_RPC_URL!); - - const privy = new PrivyClient({ - appId: process.env.PRIVY_APP_ID!, - appSecret: process.env.PRIVY_APP_SECRET!, - }); - - const recipient = new PublicKey(recipientAddress); - const mintPubkey = new PublicKey(tokenMintAddress); - const ata = getAssociatedTokenAddressInterface(mintPubkey, recipient); - - // Creates the ATA if needed and loads any compressed state into it. - // Returns TransactionInstruction[][] — almost always just one. - const instructions = await createLoadAtaInstructions( - connection, ata, recipient, mintPubkey, recipient, - ); - - // Sign and send each batch via Privy - const walletId = process.env.TREASURY_WALLET_ID!; - const authorizationKey = process.env.TREASURY_AUTHORIZATION_KEY!; - const signatures: string[] = []; - - for (const ixs of instructions) { - const tx = new Transaction().add(...ixs); - const {blockhash} = await connection.getLatestBlockhash(); - tx.recentBlockhash = blockhash; - tx.feePayer = recipient; - - const {signed_transaction} = await privy.wallets().solana().signTransaction( - walletId, { - transaction: tx.serialize({requireAllSignatures: false}), - authorization_context: {authorization_private_keys: [authorizationKey]}, - }, - ) as any; - - const sig = await connection.sendRawTransaction( - Buffer.from(signed_transaction, 'base64'), - {skipPreflight: false, preflightCommitment: 'confirmed'}, - ); - await connection.confirmTransaction(sig, 'confirmed'); - signatures.push(sig); - } - - return signatures.length > 0 ? signatures[signatures.length - 1] : null; -}; - -export default receiveLightTokens; - ``` diff --git a/snippets/code-snippets/privy/receive/react.mdx b/snippets/code-snippets/privy/receive/react.mdx index f85e0fd..9e21246 100644 --- a/snippets/code-snippets/privy/receive/react.mdx +++ b/snippets/code-snippets/privy/receive/react.mdx @@ -1,61 +1,2 @@ ```typescript -import { useState } from 'react'; -import { PublicKey } from '@solana/web3.js'; -import { - createLoadAtaInstructions, - getAssociatedTokenAddressInterface, -} from '@lightprotocol/compressed-token/unified'; -import { createRpc } from '@lightprotocol/stateless.js'; -import type { ConnectedStandardSolanaWallet } from '@privy-io/js-sdk-core'; -import { useSignTransaction } from '@privy-io/react-auth/solana'; -import { signAndSendBatches } from './signAndSendBatches'; - -type SignTransactionFn = ReturnType['signTransaction']; - -export interface ReceiveParams { - ownerPublicKey: string; - mint: string; -} - -export interface ReceiveArgs { - params: ReceiveParams; - wallet: ConnectedStandardSolanaWallet; - signTransaction: SignTransactionFn; -} - -export function useReceive() { - const [isLoading, setIsLoading] = useState(false); - - const receive = async (args: ReceiveArgs): Promise => { - setIsLoading(true); - - try { - const { params, wallet, signTransaction } = args; - - const rpc = createRpc(import.meta.env.VITE_HELIUS_RPC_URL); - - const owner = new PublicKey(params.ownerPublicKey); - const mintPubkey = new PublicKey(params.mint); - const ata = getAssociatedTokenAddressInterface(mintPubkey, owner); - - // Returns TransactionInstruction[][]. - // Each inner array is one transaction. - // Almost always returns just one. - const instructions = await createLoadAtaInstructions( - rpc, ata, owner, mintPubkey, owner, - ); - - return await signAndSendBatches(instructions, { - rpc, - feePayer: owner, - wallet, - signTransaction, - }); - } finally { - setIsLoading(false); - } - }; - - return { receive, isLoading }; -} ``` diff --git a/snippets/code-snippets/privy/transfer/nodejs.mdx b/snippets/code-snippets/privy/transfer/nodejs.mdx index 60b51ea..4a0844e 100644 --- a/snippets/code-snippets/privy/transfer/nodejs.mdx +++ b/snippets/code-snippets/privy/transfer/nodejs.mdx @@ -24,7 +24,7 @@ const transferLightTokens = async ( const fromPubkey = new PublicKey(fromAddress); const toPubkey = new PublicKey(toAddress); const mintPubkey = new PublicKey(tokenMintAddress); - const tokenAmount = Math.round(amount * Math.pow(10, decimals)); + const tokenAmount = Math.floor(amount * Math.pow(10, decimals)); // Loads cold (compressed), SPL, and Token 2022 balances into the Light Token associated token account before transfer. // Returns TransactionInstruction[][] — send [0..n-2] in parallel, then [n-1] last. diff --git a/snippets/code-snippets/privy/unwrap/nodejs.mdx b/snippets/code-snippets/privy/unwrap/nodejs.mdx index 4d3b898..1bc631e 100644 --- a/snippets/code-snippets/privy/unwrap/nodejs.mdx +++ b/snippets/code-snippets/privy/unwrap/nodejs.mdx @@ -23,14 +23,14 @@ const unwrapTokens = async ( const fromPubkey = new PublicKey(fromAddress); const mintPubkey = new PublicKey(tokenMintAddress); - const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); + const tokenAmount = BigInt(Math.floor(amount * Math.pow(10, decimals))); // Auto-detect token program (SPL vs Token 2022) from mint account owner const mintAccountInfo = await connection.getAccountInfo(mintPubkey); if (!mintAccountInfo) throw new Error(`Mint account ${tokenMintAddress} not found`); const tokenProgramId = mintAccountInfo.owner; - // Destination: SPL/Token 2022 associated token account + // Destination: SPL/T22 associated token account const splAta = getAssociatedTokenAddressSync(mintPubkey, fromPubkey, false, tokenProgramId); // Returns TransactionInstruction[][]. diff --git a/snippets/code-snippets/privy/unwrap/react.mdx b/snippets/code-snippets/privy/unwrap/react.mdx index d2eb4e6..0eeafb5 100644 --- a/snippets/code-snippets/privy/unwrap/react.mdx +++ b/snippets/code-snippets/privy/unwrap/react.mdx @@ -41,12 +41,12 @@ export function useUnwrap() { const mintPubkey = new PublicKey(mint); const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); - // Auto-detect token program (SPL vs Token 2022) from mint account owner + // Auto-detect token program (SPL vs T22) from mint account owner const mintAccountInfo = await rpc.getAccountInfo(mintPubkey); if (!mintAccountInfo) throw new Error(`Mint account ${mint} not found`); const tokenProgramId = mintAccountInfo.owner; - // Destination: SPL/Token 2022 associated token account + // Destination: SPL/T22 associated token account const splAta = getAssociatedTokenAddressSync(mintPubkey, owner, false, tokenProgramId); // Returns TransactionInstruction[][]. diff --git a/snippets/code-snippets/privy/wrap/nodejs.mdx b/snippets/code-snippets/privy/wrap/nodejs.mdx index 20fe72f..bf34ca1 100644 --- a/snippets/code-snippets/privy/wrap/nodejs.mdx +++ b/snippets/code-snippets/privy/wrap/nodejs.mdx @@ -26,7 +26,7 @@ const wrapTokens = async ( const fromPubkey = new PublicKey(fromAddress); const mintPubkey = new PublicKey(tokenMintAddress); - const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); + const tokenAmount = BigInt(Math.floor(amount * Math.pow(10, decimals))); // Get SPL interface info — determines whether mint uses SPL or Token 2022 const splInterfaceInfos = await getSplInterfaceInfos(connection, mintPubkey); diff --git a/snippets/code-snippets/privy/wrap/react.mdx b/snippets/code-snippets/privy/wrap/react.mdx index 4f8a238..8262a39 100644 --- a/snippets/code-snippets/privy/wrap/react.mdx +++ b/snippets/code-snippets/privy/wrap/react.mdx @@ -43,7 +43,7 @@ export function useWrap() { const mintPubkey = new PublicKey(mint); const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); - // Get SPL interface info — determines whether mint uses SPL or Token 2022 + // Get SPL interface info — determines whether mint uses SPL or T22 const splInterfaceInfos = await getSplInterfaceInfos(rpc, mintPubkey); const splInterfaceInfo = splInterfaceInfos.find( (info) => info.isInitialized, @@ -51,7 +51,7 @@ export function useWrap() { if (!splInterfaceInfo) throw new Error('No SPL interface found for this mint'); const { tokenProgram } = splInterfaceInfo; - // Derive source associated token account using the mint's token program (SPL or Token 2022) + // Derive source associated token account using the mint's token program (SPL or T22) const splAta = getAssociatedTokenAddressSync(mintPubkey, owner, false, tokenProgram); const ataAccount = await getAccount(rpc, splAta, undefined, tokenProgram); if (ataAccount.amount < BigInt(tokenAmount)) { diff --git a/snippets/code-snippets/wallet-adapter/balances/react.mdx b/snippets/code-snippets/wallet-adapter/balances/react.mdx index 457b697..0c9f60e 100644 --- a/snippets/code-snippets/wallet-adapter/balances/react.mdx +++ b/snippets/code-snippets/wallet-adapter/balances/react.mdx @@ -1,6 +1,6 @@ ```typescript import { useState, useCallback } from 'react'; -import { PublicKey } from '@solana/web3.js'; +import { PublicKey, LAMPORTS_PER_SOL } from '@solana/web3.js'; import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, getMint } from '@solana/spl-token'; import { createRpc } from '@lightprotocol/stateless.js'; import { @@ -28,9 +28,7 @@ export function useUnifiedBalance() { setIsLoading(true); try { - const rpc = import.meta.env.VITE_LOCALNET === 'true' - ? createRpc() - : createRpc(import.meta.env.VITE_HELIUS_RPC_URL); + const rpc = createRpc(import.meta.env.VITE_HELIUS_RPC_URL); const owner = new PublicKey(ownerAddress); // Per-mint accumulator @@ -133,21 +131,16 @@ export function useUnifiedBalance() { // 7. Assemble TokenBalance[] const result: TokenBalance[] = []; - // Pull WSOL data from mintMap (if user has WSOL in token accounts) - const WSOL_MINT = 'So11111111111111111111111111111111111111112'; - const wsolEntry = mintMap.get(WSOL_MINT); - mintMap.delete(WSOL_MINT); // prevent duplicate row - - // SOL entry: native SOL + WSOL Light Token balances + // SOL entry result.push({ - mint: WSOL_MINT, + mint: 'So11111111111111111111111111111111111111112', decimals: 9, isNative: true, - hot: wsolEntry?.hot ?? 0n, - cold: wsolEntry?.cold ?? 0n, + hot: 0n, + cold: 0n, spl: BigInt(solLamports), - t22: wsolEntry?.t22 ?? 0n, - unified: (wsolEntry?.hot ?? 0n) + (wsolEntry?.cold ?? 0n), + t22: 0n, + unified: 0n, }); // Token entries diff --git a/snippets/code-snippets/wallet-adapter/receive/react.mdx b/snippets/code-snippets/wallet-adapter/receive/react.mdx index 1c3e9b7..9e21246 100644 --- a/snippets/code-snippets/wallet-adapter/receive/react.mdx +++ b/snippets/code-snippets/wallet-adapter/receive/react.mdx @@ -1,57 +1,2 @@ ```typescript -import { useState } from 'react'; -import { PublicKey } from '@solana/web3.js'; -import { - createLoadAtaInstructions, - getAssociatedTokenAddressInterface, -} from '@lightprotocol/compressed-token/unified'; -import { createRpc } from '@lightprotocol/stateless.js'; -import { signAndSendBatches, type SignTransactionFn } from './signAndSendBatches'; - -export interface ReceiveParams { - ownerPublicKey: string; - mint: string; -} - -export interface ReceiveArgs { - params: ReceiveParams; - signTransaction: SignTransactionFn; -} - -export function useReceive() { - const [isLoading, setIsLoading] = useState(false); - - const receive = async (args: ReceiveArgs): Promise => { - setIsLoading(true); - - try { - const { params, signTransaction } = args; - - const rpc = import.meta.env.VITE_LOCALNET === 'true' - ? createRpc() - : createRpc(import.meta.env.VITE_HELIUS_RPC_URL); - - const owner = new PublicKey(params.ownerPublicKey); - const mintPubkey = new PublicKey(params.mint); - const ata = getAssociatedTokenAddressInterface(mintPubkey, owner); - - // Returns TransactionInstruction[][]. - // Each inner array is one transaction. - // Almost always returns just one. - const instructions = await createLoadAtaInstructions( - rpc, ata, owner, mintPubkey, owner, - ); - - return await signAndSendBatches(instructions, { - rpc, - feePayer: owner, - signTransaction, - }); - } finally { - setIsLoading(false); - } - }; - - return { receive, isLoading }; -} ``` diff --git a/snippets/code-snippets/wallet-adapter/transaction-history/react.mdx b/snippets/code-snippets/wallet-adapter/transaction-history/react.mdx index 17cfdca..1c98218 100644 --- a/snippets/code-snippets/wallet-adapter/transaction-history/react.mdx +++ b/snippets/code-snippets/wallet-adapter/transaction-history/react.mdx @@ -29,9 +29,7 @@ export function useTransactionHistory() { setError(null); try { - const rpc = import.meta.env.VITE_LOCALNET === 'true' - ? createRpc() - : createRpc(import.meta.env.VITE_HELIUS_RPC_URL); + const rpc = createRpc(import.meta.env.VITE_HELIUS_RPC_URL); const owner = new PublicKey(ownerAddress); const result = await rpc.getSignaturesForOwnerInterface(owner); diff --git a/snippets/code-snippets/wallet-adapter/transfer/react.mdx b/snippets/code-snippets/wallet-adapter/transfer/react.mdx index 59e55bd..c0d635f 100644 --- a/snippets/code-snippets/wallet-adapter/transfer/react.mdx +++ b/snippets/code-snippets/wallet-adapter/transfer/react.mdx @@ -1,16 +1,12 @@ ```typescript import { useState } from 'react'; -import { PublicKey, type TransactionInstruction } from '@solana/web3.js'; +import { PublicKey } from '@solana/web3.js'; import { createTransferInterfaceInstructions, } from '@lightprotocol/compressed-token/unified'; import { createRpc } from '@lightprotocol/stateless.js'; import { signAndSendBatches, type SignTransactionFn } from './signAndSendBatches'; -// For native SOL, the user must wrap SOL → WSOL first (via useWrap or -// the payments toolkit). createTransferInterfaceInstructions works with -// WSOL like any other SPL token once it exists in a token account. - export interface TransferParams { ownerPublicKey: string; mint: string; @@ -34,19 +30,19 @@ export function useTransfer() { const { params, signTransaction } = args; const { ownerPublicKey, mint, toAddress, amount, decimals = 9 } = params; - const rpc = import.meta.env.VITE_LOCALNET === 'true' - ? createRpc() - : createRpc(import.meta.env.VITE_HELIUS_RPC_URL); + const rpc = createRpc(import.meta.env.VITE_HELIUS_RPC_URL); const owner = new PublicKey(ownerPublicKey); const mintPubkey = new PublicKey(mint); const recipient = new PublicKey(toAddress); const tokenAmount = Math.round(amount * Math.pow(10, decimals)); - const instructions: TransactionInstruction[][] = - await createTransferInterfaceInstructions( - rpc, owner, mintPubkey, tokenAmount, owner, recipient, - ); + // Returns TransactionInstruction[][]. + // Each inner array is one transaction. + // Almost always returns just one. + const instructions = await createTransferInterfaceInstructions( + rpc, owner, mintPubkey, tokenAmount, owner, recipient, + ); const signature = await signAndSendBatches(instructions, { rpc, diff --git a/snippets/code-snippets/wallet-adapter/unwrap/react.mdx b/snippets/code-snippets/wallet-adapter/unwrap/react.mdx index 43f1a38..9588eaf 100644 --- a/snippets/code-snippets/wallet-adapter/unwrap/react.mdx +++ b/snippets/code-snippets/wallet-adapter/unwrap/react.mdx @@ -30,20 +30,18 @@ export function useUnwrap() { const { params, signTransaction } = args; const { ownerPublicKey, mint, amount, decimals = 9 } = params; - const rpc = import.meta.env.VITE_LOCALNET === 'true' - ? createRpc() - : createRpc(import.meta.env.VITE_HELIUS_RPC_URL); + const rpc = createRpc(import.meta.env.VITE_HELIUS_RPC_URL); const owner = new PublicKey(ownerPublicKey); const mintPubkey = new PublicKey(mint); const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); - // Auto-detect token program (SPL vs Token 2022) from mint account owner + // Auto-detect token program (SPL vs T22) from mint account owner const mintAccountInfo = await rpc.getAccountInfo(mintPubkey); if (!mintAccountInfo) throw new Error(`Mint account ${mint} not found`); const tokenProgramId = mintAccountInfo.owner; - // Destination: SPL/Token 2022 associated token account + // Destination: SPL/T22 associated token account const splAta = getAssociatedTokenAddressSync(mintPubkey, owner, false, tokenProgramId); // Returns TransactionInstruction[][]. diff --git a/snippets/code-snippets/wallet-adapter/wrap/react.mdx b/snippets/code-snippets/wallet-adapter/wrap/react.mdx index 8a96b9f..37f4524 100644 --- a/snippets/code-snippets/wallet-adapter/wrap/react.mdx +++ b/snippets/code-snippets/wallet-adapter/wrap/react.mdx @@ -33,15 +33,13 @@ export function useWrap() { const { params, signTransaction } = args; const { ownerPublicKey, mint, amount, decimals = 9 } = params; - const rpc = import.meta.env.VITE_LOCALNET === 'true' - ? createRpc() - : createRpc(import.meta.env.VITE_HELIUS_RPC_URL); + const rpc = createRpc(import.meta.env.VITE_HELIUS_RPC_URL); const owner = new PublicKey(ownerPublicKey); const mintPubkey = new PublicKey(mint); const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); - // Get SPL interface info — determines whether mint uses SPL or Token 2022 + // Get SPL interface info — determines whether mint uses SPL or T22 const splInterfaceInfos = await getSplInterfaceInfos(rpc, mintPubkey); const splInterfaceInfo = splInterfaceInfos.find( (info) => info.isInitialized, @@ -49,7 +47,7 @@ export function useWrap() { if (!splInterfaceInfo) throw new Error('No SPL interface found for this mint'); const { tokenProgram } = splInterfaceInfo; - // Derive source associated token account using the mint's token program (SPL or Token 2022) + // Derive source associated token account using the mint's token program (SPL or T22) const splAta = getAssociatedTokenAddressSync(mintPubkey, owner, false, tokenProgram); const ataAccount = await getAccount(rpc, splAta, undefined, tokenProgram); if (ataAccount.amount < BigInt(tokenAmount)) { diff --git a/snippets/overview-tables/light-token-client-examples-table.mdx b/snippets/overview-tables/light-token-client-examples-table.mdx index 0b532f2..53c5906 100644 --- a/snippets/overview-tables/light-token-client-examples-table.mdx +++ b/snippets/overview-tables/light-token-client-examples-table.mdx @@ -14,7 +14,12 @@ |---------|--------|-------------|------| | **approve** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-approve.ts) | — | [Docs](/light-token/cookbook/approve-revoke) | | **create-ata** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-ata.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/create-ata.ts) | [Docs](/light-token/cookbook/create-ata) | +| **create-ata-explicit-rent-sponsor** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-ata-explicit-rent-sponsor.ts) | — | [Docs](/light-token/cookbook/create-ata) | | **create-mint** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-mint.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/create-mint.ts) | [Docs](/light-token/cookbook/create-mint) | +| **create-spl-interface** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-spl-interface.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/create-spl-interface.ts) | [Docs](light-token/cookbook/add-interface-pda) | +| **create-spl-mint** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-spl-mint.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/create-spl-mint.ts) | [Docs](/light-token/cookbook/create-mint#create-spl-mint-with-interface-pda) | +| **create-t22-mint** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-t22-mint.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/create-t22-mint.ts) | [Docs](/light-token/cookbook/create-mint#create-token-2022-mint-with-interface-pda) | +| **delegate-transfer** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-transfer.ts) | — | [Docs](/light-token/cookbook/transfer-delegated) | | **load-ata** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/load-ata.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/load-ata.ts) | [Docs](/light-token/cookbook/load-ata) | | **mint-to** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/mint-to.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/mint-to.ts) | [Docs](/light-token/cookbook/mint-to) | | **revoke** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-revoke.ts) | — | [Docs](/light-token/cookbook/approve-revoke) | @@ -42,3 +47,18 @@ | **transfer-interface** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/actions/transfer_interface.rs) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/instructions/transfer_interface.rs) | [Docs](/light-token/cookbook/transfer-interface) | | **unwrap** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/actions/unwrap.rs) | — | [Docs](/light-token/cookbook/wrap-unwrap) | | **wrap** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/actions/wrap.rs) | — | [Docs](/light-token/cookbook/wrap-unwrap) | + +### Extensions + +| | | | +|---------|-------------|------| +| **close-mint** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/close-mint.ts) | [Docs](/light-token/extensions/close-mint) | +| **confidential-transfer** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/confidential-transfer.ts) | [Docs](/light-token/extensions/confidential-transfer) | +| **default-account-state** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/default-account-state.ts) | [Docs](/light-token/extensions/default-account-state) | +| **interest-bearing-tokens** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/interest-bearing-tokens.ts) | [Docs](/light-token/extensions/interest-bearing-tokens) | +| **metadata-and-metadata-pointer** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/metadata-and-metadata-pointer.ts) | [Docs](/light-token/extensions/metadata-and-metadata-pointer) | +| **pausable-mint** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/pausable-mint.ts) | [Docs](/light-token/extensions/pausable-mint) | +| **permanent-delegate** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/permanent-delegate.ts) | [Docs](/light-token/extensions/permanent-delegate) | +| **token-groups-and-members** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts) | [Docs](/light-token/extensions/token-groups-and-members) | +| **transfer-fees** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-fees.ts) | [Docs](/light-token/extensions/transfer-fees) | +| **transfer-hook** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-hook.ts) | [Docs](/light-token/extensions/transfer-hook) | diff --git a/snippets/overview-tables/light-token-program-examples-table.mdx b/snippets/overview-tables/light-token-program-examples-table.mdx index 44a07ce..d59e6a5 100644 --- a/snippets/overview-tables/light-token-program-examples-table.mdx +++ b/snippets/overview-tables/light-token-program-examples-table.mdx @@ -15,7 +15,7 @@ | | Description | | |---------|-------------|------| | **counter** | Create PDA with sponsored rent-exemption | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/counter) \| [Docs](/pda/light-pda/overview) | -| **create-associated-token-account** | Create associated light-token account | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/create-ata) \| [Docs](/light-token/cookbook/create-ata) | +| **create-associated-token-account** | Create associated light-token account | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/create-associated-token-account) \| [Docs](/light-token/cookbook/create-ata) | | **create-mint** | Create light-token mint | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/create-mint) \| [Docs](/light-token/cookbook/create-mint) | | **create-token-account** | Create light-token account | [Example](https://github.com/Lightprotocol/examples-light-token/tree/main/programs/anchor/basic-macros/create-token-account) \| [Docs](/light-token/cookbook/create-token-account) | @@ -29,7 +29,7 @@ For existing programs, you can replace spl_token with light_token instructions a | **approve** | Approve delegate via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/approve/src/lib.rs) \| [Docs](/light-token/cookbook/approve-revoke) | | **burn** | Burn tokens via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/burn/src/lib.rs) \| [Docs](/light-token/cookbook/burn) | | **close** | Close token account via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/close/src/lib.rs) \| [Docs](/light-token/cookbook/close-token-account) | -| **create-associated-token-account** | Create associated light-token account via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/create-ata/src/lib.rs) \| [Docs](/light-token/cookbook/create-ata) | +| **create-associated-token-account** | Create associated light-token account via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/create-associated-token-account/src/lib.rs) \| [Docs](/light-token/cookbook/create-ata) | | **create-mint** | Create light-token mint via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/create-mint/src/lib.rs) \| [Docs](/light-token/cookbook/create-mint) | | **create-token-account** | Create light-token account via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/create-token-account/src/lib.rs) \| [Docs](/light-token/cookbook/create-token-account) | | **freeze** | Freeze token account via CPI | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/freeze/src/lib.rs) \| [Docs](/light-token/cookbook/freeze-thaw) | From a801dfa3f0adf6634c66a59bed6656725dce9c8e Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Fri, 20 Mar 2026 02:20:40 +0000 Subject: [PATCH 14/19] Fix broken links: nullifier-pda rename and verify-address path --- docs.json | 2 +- light-token/payments/verify-payments.mdx | 2 +- light-token/welcome.mdx | 2 +- pda/compressed-pdas/overview.mdx | 2 +- pda/overview.mdx | 2 +- resources/terminology.mdx | 2 +- snippets/ai-prompts/all-prompts.mdx | 2 +- snippets/ai-prompts/light-token-prompts.mdx | 2 +- snippets/ai-prompts/toolkits/nullifiers.mdx | 4 ++-- snippets/overview-tables/compressed-pdas-guides-table.mdx | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs.json b/docs.json index 50774ed..c2a00b0 100644 --- a/docs.json +++ b/docs.json @@ -370,7 +370,7 @@ }, "redirects": [ { - "source": "/pda/compressed-pdas/how-to-create-nullifier-pdas", + "source": "/pda/compressed-pdas/nullifier-pda", "destination": "https://zkcompression.com/pda/compressed-pdas/nullifier-pda" }, { diff --git a/light-token/payments/verify-payments.mdx b/light-token/payments/verify-payments.mdx index 049d7ce..2c66e04 100644 --- a/light-token/payments/verify-payments.mdx +++ b/light-token/payments/verify-payments.mdx @@ -118,7 +118,7 @@ const signatures = await connection.getSignaturesForAddress(ata); Send a single token transfer. - + Validate recipient addresses before sending. diff --git a/light-token/welcome.mdx b/light-token/welcome.mdx index d2aa169..78c0f55 100644 --- a/light-token/welcome.mdx +++ b/light-token/welcome.mdx @@ -193,7 +193,7 @@ View the [guide](/light-token/cookbook/create-ata) to create associated token ac Learn how to integrate Light Token in your stablecoin payment infrastructure. - + Prevent onchain instructions from being executed more than once. diff --git a/pda/compressed-pdas/overview.mdx b/pda/compressed-pdas/overview.mdx index 78bee24..a0c91fd 100644 --- a/pda/compressed-pdas/overview.mdx +++ b/pda/compressed-pdas/overview.mdx @@ -24,7 +24,7 @@ Compressed PDAs are suited for: - Per-user state (profiles, preferences, credentials) - DePIN node accounts and stake accounts - Nullifiers to prevent an on-chain instruction from -being executed twice (little implementation overhead and useful e.g. for [payments](/pda/compressed-pdas/how-to-create-nullifier-pdas) or [ZK programs](zk/overview)) +being executed twice (little implementation overhead and useful e.g. for [payments](/pda/compressed-pdas/nullifier-pda) or [ZK programs](zk/overview)) - App state that is written to and read from infrequently For DeFi pools, vaults, shared state, pool accounts, or config accounts, use [Light-PDA](/pda/light-pda/overview) with minimal code changes. diff --git a/pda/overview.mdx b/pda/overview.mdx index c685b65..7f51241 100644 --- a/pda/overview.mdx +++ b/pda/overview.mdx @@ -38,7 +38,7 @@ Fully compatible with existing Solana programs, but requires custom logic. > - Per-user state (profiles, preferences, credentials) > - DePIN node accounts and stake accounts > - Nullifiers to prevent an on-chain instruction from -> being executed twice (little implementation overhead and useful e.g. for [payments](/pda/compressed-pdas/how-to-create-nullifier-pdas) or [ZK programs](zk/overview)) +> being executed twice (little implementation overhead and useful e.g. for [payments](/pda/compressed-pdas/nullifier-pda) or [ZK programs](zk/overview)) > - App state that is written to and read from infrequently \ No newline at end of file diff --git a/resources/terminology.mdx b/resources/terminology.mdx index b6b7472..436d75b 100644 --- a/resources/terminology.mdx +++ b/resources/terminology.mdx @@ -301,7 +301,7 @@ The documentation provides two implementations with rent-free PDA accounts: | **Rust SDK** | [light-nullifier-program](https://crates.io/crates/light-nullifier-program) | | **TypeScript SDK** | [@lightprotocol/nullifier-program](https://www.npmjs.com/package/@lightprotocol/nullifier-program) | -> [Docs](/pda/compressed-pdas/how-to-create-nullifier-pdas) | [Skill](https://github.com/Lightprotocol/skills/tree/main/skills/payments) | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/actions/create_nullifier.rs) +> [Docs](/pda/compressed-pdas/nullifier-pda) | [Skill](https://github.com/Lightprotocol/skills/tree/main/skills/payments) | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/rust-client/actions/create_nullifier.rs) **ZK nullifier** — For ZK or privacy-preserving programs on Solana to prevent double-spending. Can be integrated with minimal code changes. diff --git a/snippets/ai-prompts/all-prompts.mdx b/snippets/ai-prompts/all-prompts.mdx index b0e7254..51816f5 100644 --- a/snippets/ai-prompts/all-prompts.mdx +++ b/snippets/ai-prompts/all-prompts.mdx @@ -70,7 +70,7 @@ Copy the prompt below or view the [guide](/light-token/wallets/gasless-transacti -Copy the prompt below or view the [guide](/pda/compressed-pdas/how-to-create-nullifier-pdas). +Copy the prompt below or view the [guide](/pda/compressed-pdas/nullifier-pda). diff --git a/snippets/ai-prompts/light-token-prompts.mdx b/snippets/ai-prompts/light-token-prompts.mdx index 1839dbf..d0215c2 100644 --- a/snippets/ai-prompts/light-token-prompts.mdx +++ b/snippets/ai-prompts/light-token-prompts.mdx @@ -60,7 +60,7 @@ Copy the prompt below or view the [guide](/light-token/payments/integration-guid -Copy the prompt below or view the [guide](/pda/compressed-pdas/how-to-create-nullifier-pdas). +Copy the prompt below or view the [guide](/pda/compressed-pdas/nullifier-pda). diff --git a/snippets/ai-prompts/toolkits/nullifiers.mdx b/snippets/ai-prompts/toolkits/nullifiers.mdx index 00a3ba5..f22b882 100644 --- a/snippets/ai-prompts/toolkits/nullifiers.mdx +++ b/snippets/ai-prompts/toolkits/nullifiers.mdx @@ -7,7 +7,7 @@ allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, T ## Create rent-free nullifier PDAs to prevent duplicate actions Context: -- Guide: https://zkcompression.com/pda/compressed-pdas/how-to-create-nullifier-pdas +- Guide: https://zkcompression.com/pda/compressed-pdas/nullifier-pda - Skills and resources index: https://zkcompression.com/skill.md - Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/zk-nullifier - Rust crates: light-nullifier-program, light-client @@ -72,7 +72,7 @@ allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, T ## Create rent-free nullifier PDAs to prevent duplicate actions Context: -- Guide: https://zkcompression.com/pda/compressed-pdas/how-to-create-nullifier-pdas +- Guide: https://zkcompression.com/pda/compressed-pdas/nullifier-pda - Skills and resources index: https://zkcompression.com/skill.md - Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/zk-nullifier - Rust crates: light-nullifier-program, light-client diff --git a/snippets/overview-tables/compressed-pdas-guides-table.mdx b/snippets/overview-tables/compressed-pdas-guides-table.mdx index 5783b13..32066e3 100644 --- a/snippets/overview-tables/compressed-pdas-guides-table.mdx +++ b/snippets/overview-tables/compressed-pdas-guides-table.mdx @@ -42,7 +42,7 @@ From 8af97289f39001556ceb9bea075e372d60ddb675 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Fri, 20 Mar 2026 02:24:52 +0000 Subject: [PATCH 15/19] Add spellcheck words: Gamal, blockhashes, supermajority, sqds --- cspell.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cspell.json b/cspell.json index 314c549..95d9c9d 100644 --- a/cspell.json +++ b/cspell.json @@ -197,7 +197,11 @@ "clippy", "Raydium", "raydium", - "USDG" + "USDG", + "Gamal", + "blockhashes", + "supermajority", + "sqds" ], "ignorePaths": [ "node_modules", From c50262beda01eac10c5f4c06a876fef5a0705d4a Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Fri, 20 Mar 2026 18:23:17 +0000 Subject: [PATCH 16/19] Remove extension guide pages, smart wallets; fix links and balance docs - Remove individual extension guide pages (kept on extensions-and-smart-wallets branch) - Remove smart wallets page (kept on extensions-and-smart-wallets branch) - Create shared extensions-table snippet with Solana docs + example links - Fix extensions overview to use shared snippet and link to Solana docs - Fix FAQ: correct getAtaInterface description, add extensions table - Fix verify-payments: split balance into Light Token and unified sections - Fix examples table: replace broken extension docs links - Flatten Extensions nav group to single page entry - Regenerate llms.txt --- .gitignore | 5 +- api-reference/solana-to-light-comparison.mdx | 12 +- docs.json | 20 +- faq.mdx | 43 ++- light-token/cookbook/approve-revoke.mdx | 4 + light-token/cookbook/transfer-delegated.mdx | 2 +- light-token/cookbook/transfer-interface.mdx | 3 - light-token/extensions/close-mint.mdx | 155 -------- .../extensions/confidential-transfer.mdx | 191 ---------- .../extensions/default-account-state.mdx | 157 -------- .../extensions/interest-bearing-tokens.mdx | 158 -------- .../metadata-and-metadata-pointer.mdx | 188 ---------- light-token/extensions/overview.mdx | 28 +- light-token/extensions/pausable-mint.mdx | 156 -------- light-token/extensions/permanent-delegate.mdx | 155 -------- .../extensions/token-groups-and-members.mdx | 217 ----------- light-token/extensions/transfer-fees.mdx | 156 -------- light-token/extensions/transfer-hook.mdx | 158 -------- light-token/payments/overview.mdx | 42 ++- light-token/payments/spend-permissions.mdx | 20 +- light-token/payments/verify-payments.mdx | 30 +- .../payments/verify-recipient-address.mdx | 2 +- light-token/wallets/overview.mdx | 2 - light-token/wallets/smart-wallets.mdx | 340 ------------------ llms.txt | 13 +- scripts/copy-extensions-snippets.sh | 54 --- scripts/generate-llms-txt.js | 2 +- skill.md | 16 - snippets/ai-prompts/all-prompts.mdx | 63 ---- snippets/ai-prompts/extensions/close-mint.mdx | 123 ------- .../extensions/confidential-transfer.mdx | 123 ------- .../extensions/default-account-state.mdx | 123 ------- .../extensions/interest-bearing-tokens.mdx | 117 ------ .../metadata-and-metadata-pointer.mdx | 117 ------ .../ai-prompts/extensions/pausable-mint.mdx | 123 ------- .../extensions/permanent-delegate.mdx | 123 ------- .../extensions/token-groups-and-members.mdx | 123 ------- .../ai-prompts/extensions/transfer-fees.mdx | 123 ------- .../ai-prompts/extensions/transfer-hook.mdx | 123 ------- snippets/ai-prompts/toolkits/payments.mdx | 4 +- snippets/ai-prompts/wallets/smart-wallets.mdx | 159 -------- .../light-token/delegate-transfer/action.mdx | 10 +- .../extensions/close-mint/action.mdx | 91 ----- .../confidential-transfer/action.mdx | 141 -------- .../default-account-state/action.mdx | 92 ----- .../extensions/interest-bearing/action.mdx | 93 ----- .../extensions/metadata-pointer/action.mdx | 120 ------- .../extensions/pausable/action.mdx | 89 ----- .../extensions/permanent-delegate/action.mdx | 91 ----- .../extensions/token-groups/action.mdx | 179 --------- .../extensions/transfer-fees/action.mdx | 94 ----- .../extensions/transfer-hook/action.mdx | 93 ----- .../light-token/load-ata/instruction.mdx | 10 +- .../delegate-transfer-instruction.mdx | 8 +- .../spend-permissions/delegate-transfer.mdx | 31 +- snippets/extensions-table.mdx | 36 +- snippets/jsx/stats-widget.jsx | 90 +++++ .../light-token-client-examples-table.mdx | 30 +- snippets/setup/extensions-setup.mdx | 18 - 59 files changed, 302 insertions(+), 4787 deletions(-) delete mode 100644 light-token/extensions/close-mint.mdx delete mode 100644 light-token/extensions/confidential-transfer.mdx delete mode 100644 light-token/extensions/default-account-state.mdx delete mode 100644 light-token/extensions/interest-bearing-tokens.mdx delete mode 100644 light-token/extensions/metadata-and-metadata-pointer.mdx delete mode 100644 light-token/extensions/pausable-mint.mdx delete mode 100644 light-token/extensions/permanent-delegate.mdx delete mode 100644 light-token/extensions/token-groups-and-members.mdx delete mode 100644 light-token/extensions/transfer-fees.mdx delete mode 100644 light-token/extensions/transfer-hook.mdx delete mode 100644 light-token/wallets/smart-wallets.mdx delete mode 100755 scripts/copy-extensions-snippets.sh delete mode 100644 snippets/ai-prompts/extensions/close-mint.mdx delete mode 100644 snippets/ai-prompts/extensions/confidential-transfer.mdx delete mode 100644 snippets/ai-prompts/extensions/default-account-state.mdx delete mode 100644 snippets/ai-prompts/extensions/interest-bearing-tokens.mdx delete mode 100644 snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx delete mode 100644 snippets/ai-prompts/extensions/pausable-mint.mdx delete mode 100644 snippets/ai-prompts/extensions/permanent-delegate.mdx delete mode 100644 snippets/ai-prompts/extensions/token-groups-and-members.mdx delete mode 100644 snippets/ai-prompts/extensions/transfer-fees.mdx delete mode 100644 snippets/ai-prompts/extensions/transfer-hook.mdx delete mode 100644 snippets/ai-prompts/wallets/smart-wallets.mdx delete mode 100644 snippets/code-snippets/light-token/extensions/close-mint/action.mdx delete mode 100644 snippets/code-snippets/light-token/extensions/confidential-transfer/action.mdx delete mode 100644 snippets/code-snippets/light-token/extensions/default-account-state/action.mdx delete mode 100644 snippets/code-snippets/light-token/extensions/interest-bearing/action.mdx delete mode 100644 snippets/code-snippets/light-token/extensions/metadata-pointer/action.mdx delete mode 100644 snippets/code-snippets/light-token/extensions/pausable/action.mdx delete mode 100644 snippets/code-snippets/light-token/extensions/permanent-delegate/action.mdx delete mode 100644 snippets/code-snippets/light-token/extensions/token-groups/action.mdx delete mode 100644 snippets/code-snippets/light-token/extensions/transfer-fees/action.mdx delete mode 100644 snippets/code-snippets/light-token/extensions/transfer-hook/action.mdx create mode 100644 snippets/jsx/stats-widget.jsx delete mode 100644 snippets/setup/extensions-setup.mdx diff --git a/.gitignore b/.gitignore index b75b7cf..96b1822 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,7 @@ docs-audit.md docs-audit.txt docs-anchor.json product-docs.json -tabs-docs.json \ No newline at end of file +tabs-docs.json + +# Local helper scripts with hardcoded paths +scripts/copy-payments-snippets.sh \ No newline at end of file diff --git a/api-reference/solana-to-light-comparison.mdx b/api-reference/solana-to-light-comparison.mdx index e217bfc..72bc912 100644 --- a/api-reference/solana-to-light-comparison.mdx +++ b/api-reference/solana-to-light-comparison.mdx @@ -140,7 +140,7 @@ const signatures = await connection.getSignaturesForAddress(ata); ## Client -Both `@lightprotocol/compressed-token` (TypeScript) and `light_token_client` (Rust) match the SPL Token API. +Both `@lightprotocol/compressed-token` (TypeScript) and `light_token_client` (Rust) are a superset of the SPL Token API. Every SPL operation has a 1:1 equivalent. The SDKs add unified balance queries (`getAtaInterface`), automatic load/decompress for cold state, wrap/unwrap for SPL and Token 2022 interop, and cross-program dispatch via `Interface` methods like `transferInterface` that auto-detect the token program. ### Create mint @@ -905,17 +905,19 @@ Transfer tokens as an approved delegate. The delegate is the transaction authori ```typescript title="Light" -import { transferDelegatedInterface } from "@lightprotocol/compressed-token/unified"; +import { transferInterface } from "@lightprotocol/compressed-token/unified"; -const tx = await transferDelegatedInterface( +const tx = await transferInterface( rpc, payer, sourceAta, mint, recipient, delegate, - owner.publicKey, - amount + amount, + undefined, + undefined, + { owner: owner.publicKey } ); ``` ```typescript title="SPL" diff --git a/docs.json b/docs.json index c2a00b0..b8132b6 100644 --- a/docs.json +++ b/docs.json @@ -65,22 +65,7 @@ "light-token/cookbook/burn" ] }, - { - "group": "Extensions", - "pages": [ - "light-token/extensions/overview", - "light-token/extensions/metadata-and-metadata-pointer", - "light-token/extensions/transfer-fees", - "light-token/extensions/transfer-hook", - "light-token/extensions/interest-bearing-tokens", - "light-token/extensions/default-account-state", - "light-token/extensions/permanent-delegate", - "light-token/extensions/close-mint", - "light-token/extensions/token-groups-and-members", - "light-token/extensions/pausable-mint", - "light-token/extensions/confidential-transfer" - ] - }, + "light-token/extensions/overview", { "group": "For Stablecoin Payments", "pages": [ @@ -118,8 +103,7 @@ "light-token/wallets/overview", "light-token/wallets/privy", "light-token/wallets/wallet-adapter", - "light-token/wallets/gasless-transactions", - "light-token/wallets/smart-wallets" + "light-token/wallets/gasless-transactions" ] }, { diff --git a/faq.mdx b/faq.mdx index e0140b6..6190cec 100644 --- a/faq.mdx +++ b/faq.mdx @@ -5,6 +5,7 @@ keywords: ["spl token vs light token comparison", "token 2022 vs light token dif --- import { CodeCompare } from "/snippets/jsx/code-compare.jsx"; +import ExtensionsTable from "/snippets/extensions-table.mdx"; import CompressibleRentExplained from "/snippets/compressible-rent-explained.mdx"; import RentSponsorshipExplained from "/snippets/rent-sponsorship-explained.mdx"; import { RentLifecycleVisualizer } from "/snippets/jsx/rent-lifecycle-visualizer.jsx"; @@ -83,8 +84,7 @@ For token distribution use cases (airdrops, claims), see [Compressed Tokens](/re -No. The `light-token-sdk` methods are a superset of the SPL-token API. -Find examples below. +No. The `light-token-sdk` methods are a superset of the SPL-token API — every SPL operation (transfer, approve, revoke, freeze, thaw, burn, close) plus unified balance aggregation, automatic load/decompress, wrap/unwrap, and cross-program dispatch. See "What does 'superset of the SPL-token API' mean?" below for details. + + +The Light Token SDK covers every SPL Token operation and adds extra capabilities: + +
- Nullifier PDAs + Nullifier PDAs Prevent replay attacks with one-time use accounts
+ + + + + + + + + + + + + + + + + + + + +
CategoryWhat it does
**Cross-program dispatch**`Interface` methods (e.g., `transferInterface`) auto-detect the token program and dispatch to SPL, Token 2022, or Light Token.
**Unified balance**`getAtaInterface` returns the Light Token ATA balance for a given mint. To include compressed (cold), SPL, and Token 2022 balances, call `loadAta` first to unify them into the ATA.
**Wrap / Unwrap**For interoperability with applications that don't support Light Token yet, you can wrap / unwrap SPL or Token 2022 tokens into Light Token associated token accounts and back.
+ + + Side-by-side mapping of every Light Token instruction against its SPL/Solana equivalent. + + + + Yes, light-token accounts can hold tokens from light, SPL, or Token 2022 mints. @@ -159,9 +192,11 @@ The account is loaded into hot account state in-flight when someone interacts wi -Light Token supports 16 Token-2022 extensions, including MetadataPointer, TokenMetadata, TransferFeeConfig, PermanentDelegate, TransferHook, and more. Some extensions have restrictions (e.g., transfer fees must be zero). +Light Token supports 16 Token-2022 extensions. Some have restrictions. + + - + Additional extensions can be requested. diff --git a/light-token/cookbook/approve-revoke.mdx b/light-token/cookbook/approve-revoke.mdx index ae79771..466b415 100644 --- a/light-token/cookbook/approve-revoke.mdx +++ b/light-token/cookbook/approve-revoke.mdx @@ -91,6 +91,10 @@ import SupportFooter from "/snippets/support-footer.mdx"; [delegate-approve.ts](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-approve.ts) | [delegate-revoke.ts](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-revoke.ts) + | + [delegate-approve (instruction)](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/delegate-approve.ts) + | + [delegate-revoke (instruction)](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/delegate-revoke.ts) diff --git a/light-token/cookbook/transfer-delegated.mdx b/light-token/cookbook/transfer-delegated.mdx index 1a8c956..636a9da 100644 --- a/light-token/cookbook/transfer-delegated.mdx +++ b/light-token/cookbook/transfer-delegated.mdx @@ -11,7 +11,7 @@ import DelegateTransferAction from "/snippets/code-snippets/payments/spend-permi import DelegateTransferInstruction from "/snippets/code-snippets/payments/spend-permissions/delegate-transfer-instruction.mdx"; import SupportFooter from "/snippets/support-footer.mdx"; -`transferDelegatedInterface` transfers tokens from an associated token account as an approved delegate. The delegate is the transaction authority. Only the delegate and fee payer sign; the owner's signature is not required. +`transferInterface` with `{ owner }` transfers tokens from an associated token account as an approved delegate. The delegate is the transaction authority. Only the delegate and fee payer sign; the owner's signature is not required. - The recipient is a wallet address (associated token account derived and created internally) - The amount must be within the approved allowance diff --git a/light-token/cookbook/transfer-interface.mdx b/light-token/cookbook/transfer-interface.mdx index a78879f..885f141 100644 --- a/light-token/cookbook/transfer-interface.mdx +++ b/light-token/cookbook/transfer-interface.mdx @@ -163,9 +163,6 @@ const { rest: loads, last: transfer } = sliceLast(batches); - -Both `transferInterface` and `transferToAccountInterface` reject off-curve owners. For PDA-owned source accounts (smart wallets), use [`createLightTokenTransferInstruction`](/light-token/wallets/smart-wallets). - diff --git a/light-token/extensions/close-mint.mdx b/light-token/extensions/close-mint.mdx deleted file mode 100644 index a4a93c5..0000000 --- a/light-token/extensions/close-mint.mdx +++ /dev/null @@ -1,155 +0,0 @@ ---- -title: "Close mint" -sidebarTitle: "Close mint" -description: "Configure the MintCloseAuthority extension to allow closing a mint account and reclaiming rent using Light Token." -keywords: ["close mint light token", "mint close authority solana", "token 2022 close mint"] ---- - -import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; -import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; -import CloseMintAiPrompt from "/snippets/ai-prompts/extensions/close-mint.mdx"; -import CloseMintAction from "/snippets/code-snippets/light-token/extensions/close-mint/action.mdx"; - -A designated authority can close a mint account and reclaim its rent-exempt lamports after all tokens have been burned and the total supply reaches zero. - - -Set the `compression_only` flag when creating token accounts for this mint. Use `transferInterface` for transfers as usual. - - -## Key Parameters - -MintCloseAuthority is configured with one parameter: - -| Parameter | Description | -|-----------|-------------| -| `closeAuthority` | The public key authorized to close the mint account and reclaim its rent-exempt lamports. | - -Standard SPL mints cannot be closed once created, leaving rent-exempt lamports locked permanently. MintCloseAuthority adds a close authority that can reclaim those lamports after the total supply reaches zero. - -## Use MintCloseAuthority With Light Token - - - - - - - - -### Create a Token-2022 Mint With Close Authority - - - - -```typescript -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - ExtensionType, - getMintLen, - createInitializeMint2Instruction, - createInitializeMintCloseAuthorityInstruction, -} from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const decimals = 9; - -// Calculate space for mint + MintCloseAuthority extension -const mintLen = getMintLen([ExtensionType.MintCloseAuthority]); -const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - -// Create account -const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, -}); - -// Initialize MintCloseAuthority extension -const initMintCloseAuthorityIx = createInitializeMintCloseAuthorityInstruction( - mintKeypair.publicKey, - payer.publicKey, // close authority - TOKEN_2022_PROGRAM_ID, -); - -// Initialize mint -const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID, -); - -// Register interface PDA with Light Token -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); - -const tx = new Transaction().add( - createAccountIx, - initMintCloseAuthorityIx, - initMintIx, - createSplInterfaceIx -); - -const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, -]); -``` - - - - - - -`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the MintCloseAuthority extension, use the instruction approach shown in the other tab. - - - - - -### Create Interface PDA for Existing Mint - -If you already have a Token-2022 mint with MintCloseAuthority, create an interface PDA with Light Token. - -```typescript -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); -``` - - - - - - - -## Related Guides - - - - - - - diff --git a/light-token/extensions/confidential-transfer.mdx b/light-token/extensions/confidential-transfer.mdx deleted file mode 100644 index 2ba06c8..0000000 --- a/light-token/extensions/confidential-transfer.mdx +++ /dev/null @@ -1,191 +0,0 @@ ---- -title: "Confidential transfer" -sidebarTitle: "Confidential transfer" -description: "Configure the ConfidentialTransferMint, ConfidentialTransferFeeConfig, and ConfidentialMintBurn extensions for encrypted token amounts using Light Token." -keywords: ["confidential transfer light token", "confidential transfer solana", "token 2022 confidential transfer"] ---- - -import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; -import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; -import ConfidentialTransferAiPrompt from "/snippets/ai-prompts/extensions/confidential-transfer.mdx"; - -Encrypt token transfer amounts using ElGamal encryption so they are not visible on-chain, while keeping account addresses public and balances auditable by a designated auditor key. - - -Light Token supports confidential transfer extensions in their **initialized-but-disabled state** only. You can create Token-2022 mints with these extensions configured and register them with Light Token, but the confidential transfer features (encrypted amounts, confidential fees, confidential minting/burning) cannot be actively used through Light Token. - - -## Key Parameters - -The confidential transfer family includes three extensions: - -| Extension | Parameters | Light Token restriction | -|-----------|------------|----------------------| -| `ConfidentialTransferMint` | `authority`, `autoApproveNewAccounts`, `auditorElGamalPubkey` | Initialized but **not enabled**. The extension can exist on the mint, but encrypted transfers cannot be performed through Light Token. | -| `ConfidentialTransferFeeConfig` | `authority`, `withdrawWithheldAuthorityElGamalPubkey`, `harvestToMintEnabled`, `withheldAmount` | Fees **must be zero**. The extension can be initialized for compatibility, but confidential fee collection is not supported. | -| `ConfidentialMintBurn` | `confidentialSupply`, `decryptableSupply`, `supplyElGamalPubkey` | Initialized but **not enabled**. The extension can exist on the mint, but encrypted minting and burning cannot be performed through Light Token. | - -## Use Confidential Transfer With Light Token - - - - - - - - -### Create a Token-2022 Mint With ConfidentialTransferMint - -```typescript -import { - Keypair, - PublicKey, - SystemProgram, - Transaction, - TransactionInstruction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - ExtensionType, - TOKEN_2022_PROGRAM_ID, - createInitializeMint2Instruction, - getMintLen, -} from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -/** - * Build the InitializeMint instruction for ConfidentialTransferMint. - * - * The @solana/spl-token SDK defines ExtensionType.ConfidentialTransferMint - * but does not yet export a helper for this instruction, so we construct - * it manually using the Token-2022 instruction layout. - */ -function createInitializeConfidentialTransferMintIx( - mint: PublicKey, - authority: PublicKey | null, - autoApproveNewAccounts: boolean, - auditorElGamalPubkey: Uint8Array | null, -): TransactionInstruction { - // TokenInstruction::ConfidentialTransferExtension = 27 - // ConfidentialTransferInstruction::InitializeMint = 0 - const data = Buffer.alloc(2 + 1 + 32 + 1 + 1 + 32); - let offset = 0; - data.writeUInt8(27, offset); offset += 1; // TokenInstruction - data.writeUInt8(0, offset); offset += 1; // InitializeMint sub-instruction - - // authority (COption): 1 byte tag + 32 bytes - if (authority) { - data.writeUInt8(1, offset); offset += 1; - authority.toBuffer().copy(data, offset); offset += 32; - } else { - data.writeUInt8(0, offset); offset += 1; - offset += 32; - } - - // auto_approve_new_accounts: bool (1 byte) - data.writeUInt8(autoApproveNewAccounts ? 1 : 0, offset); offset += 1; - - // auditor_elgamal_pubkey (COption): 1 byte tag + 32 bytes - if (auditorElGamalPubkey) { - data.writeUInt8(1, offset); offset += 1; - Buffer.from(auditorElGamalPubkey).copy(data, offset); - } else { - data.writeUInt8(0, offset); offset += 1; - } - - return new TransactionInstruction({ - keys: [{ pubkey: mint, isSigner: false, isWritable: true }], - programId: TOKEN_2022_PROGRAM_ID, - data, - }); -} - -const mintKeypair = Keypair.generate(); -const decimals = 9; - -// Calculate space including ConfidentialTransferMint extension -const mintLen = getMintLen([ExtensionType.ConfidentialTransferMint]); -const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - -// Create account -const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, -}); - -// Initialize ConfidentialTransferMint extension (must come before mint init) -// auto_approve_new_accounts: false — extension is initialized but not enabled -// auditor_elgamal_pubkey: null — no auditor configured -const initConfidentialTransferIx = createInitializeConfidentialTransferMintIx( - mintKeypair.publicKey, - payer.publicKey, // authority - false, // auto_approve_new_accounts (not enabled) - null, // auditor_elgamal_pubkey -); - -// Initialize mint -const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID, -); - -// Register interface PDA with Light Token -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); - -const tx = new Transaction().add( - createAccountIx, - initConfidentialTransferIx, - initMintIx, - createSplInterfaceIx, -); - -const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, -]); -``` - -### Create Interface PDA for Existing Mint - -If you already have a Token-2022 mint with ConfidentialTransferMint, create an interface PDA with Light Token. - -```typescript -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); -``` - - - - - - - -## Related Guides - - - - - - - diff --git a/light-token/extensions/default-account-state.mdx b/light-token/extensions/default-account-state.mdx deleted file mode 100644 index 6ae809c..0000000 --- a/light-token/extensions/default-account-state.mdx +++ /dev/null @@ -1,157 +0,0 @@ ---- -title: "Default account state" -sidebarTitle: "Default account state" -description: "Configure the DefaultAccountState extension to set the initial state for newly created token accounts using Light Token." -keywords: ["default account state light token", "default account state solana", "token 2022 default account state"] ---- - -import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; -import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; -import DefaultAccountStateAiPrompt from "/snippets/ai-prompts/extensions/default-account-state.mdx"; -import DefaultAccountStateAction from "/snippets/code-snippets/light-token/extensions/default-account-state/action.mdx"; - -Every new token account created under a mint starts in a specified state, such as frozen, requiring the freeze authority to thaw accounts before holders can transact. - - -Set the `compression_only` flag when creating token accounts for this mint. Use `transferInterface` for transfers as usual. - - -## Key Parameters - -DefaultAccountState is configured with two parameters: - -| Parameter | Description | -|-----------|-------------| -| `state` | The initial `AccountState` for new token accounts. Set to `Frozen` to require approval before transacting. | -| `freezeAuthority` | Authority that can thaw frozen accounts and update the default state. **Required when the default state is `Frozen`.** | - -When a new token account is created for this mint, the token program automatically sets its state to the configured default. If the default is `Frozen`, the account cannot send or receive tokens until the freeze authority thaws it. - -## Use DefaultAccountState With Light Token - - - - - - - - -### Create a Token-2022 Mint With Default Account State - - - - -```typescript -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - ExtensionType, - getMintLen, - createInitializeMint2Instruction, - createInitializeDefaultAccountStateInstruction, - AccountState, -} from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const decimals = 9; - -// Calculate space for mint + DefaultAccountState extension -const mintLen = getMintLen([ExtensionType.DefaultAccountState]); -const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - -// Create account -const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, -}); - -// Initialize DefaultAccountState extension -const initDefaultAccountStateIx = createInitializeDefaultAccountStateInstruction( - mintKeypair.publicKey, - AccountState.Frozen, - TOKEN_2022_PROGRAM_ID, -); - -// Initialize mint -const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - payer.publicKey, // freeze authority (required for frozen default state) - TOKEN_2022_PROGRAM_ID, -); - -// Register interface PDA with Light Token -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); - -const tx = new Transaction().add( - createAccountIx, - initDefaultAccountStateIx, - initMintIx, - createSplInterfaceIx -); - -const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, -]); -``` - - - - - - -`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the DefaultAccountState extension, use the instruction approach shown in the other tab. - - - - - -### Create Interface PDA for Existing Mint - -If you already have a Token-2022 mint with DefaultAccountState, create an interface PDA with Light Token. - -```typescript -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); -``` - - - - - - - -## Related Guides - - - - - - - diff --git a/light-token/extensions/interest-bearing-tokens.mdx b/light-token/extensions/interest-bearing-tokens.mdx deleted file mode 100644 index 8398d2e..0000000 --- a/light-token/extensions/interest-bearing-tokens.mdx +++ /dev/null @@ -1,158 +0,0 @@ ---- -title: "Interest bearing tokens" -sidebarTitle: "Interest bearing tokens" -description: "Configure the InterestBearingConfig extension to display UI-adjusted balances that accrue interest over time using Light Token." -keywords: ["interest bearing light token", "interest bearing solana", "token 2022 interest bearing"] ---- - -import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; -import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; -import InterestBearingTokensAiPrompt from "/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx"; -import InterestBearingAction from "/snippets/code-snippets/light-token/extensions/interest-bearing/action.mdx"; - -## Key Parameters - -A configurable interest rate on the mint lets clients display a UI-adjusted balance that grows over time, while the on-chain token balance remains unchanged. - -InterestBearingConfig is configured with these parameters: - -| Parameter | Description | -|-----------|-------------| -| `rateAuthority` | Account authorized to update the interest rate after initialization. | -| `currentRate` | Active interest rate in basis points (e.g., 500 = 5%). | -| `initializationTimestamp` | Network timestamp recorded when the extension is created. | -| `lastUpdateTimestamp` | Network timestamp of the most recent rate change, used as the reference for interest calculations. | -| `preUpdateAverageRate` | Previous rate value preserved when the rate authority updates `currentRate`. | - -This extension is fully supported by Light Token without restrictions. - -## Use InterestBearingConfig With Light Token - - - - - - - - -### Create a Token-2022 Mint With Interest Bearing Config - - - - -```typescript -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - getMintLen, - createInitializeMint2Instruction, - ExtensionType, - createInitializeInterestBearingMintInstruction, -} from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const decimals = 9; -const rate = 500; // 5% interest rate in basis points - -// Calculate space for mint + InterestBearingConfig extension -const mintLen = getMintLen([ExtensionType.InterestBearingConfig]); -const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - -// Create account -const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, -}); - -// Initialize InterestBearingConfig -const initInterestBearingIx = - createInitializeInterestBearingMintInstruction( - mintKeypair.publicKey, - payer.publicKey, // rate authority - rate, - TOKEN_2022_PROGRAM_ID - ); - -// Initialize mint -const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, - null, - TOKEN_2022_PROGRAM_ID -); - -// Register interface PDA with Light Token -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); - -const tx = new Transaction().add( - createAccountIx, - initInterestBearingIx, - initMintIx, - createSplInterfaceIx -); - -const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, -]); -``` - - - - - - -`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the InterestBearingConfig extension, use the instruction approach shown in the other tab. - - - - - -### Create Interface PDA for Existing Mint - -If you already have a Token-2022 mint with InterestBearingConfig, create an interface PDA with Light Token. - -```typescript -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); -``` - - - - - - - -## Related Guides - - - - - - - diff --git a/light-token/extensions/metadata-and-metadata-pointer.mdx b/light-token/extensions/metadata-and-metadata-pointer.mdx deleted file mode 100644 index eafbf14..0000000 --- a/light-token/extensions/metadata-and-metadata-pointer.mdx +++ /dev/null @@ -1,188 +0,0 @@ ---- -title: "Metadata and metadata pointer" -sidebarTitle: "Metadata and metadata pointer" -description: "Configure the MetadataPointer and TokenMetadata extensions to store token name, symbol, and URI on a Token 2022 mint using Light Token." -keywords: ["metadata pointer light token", "token metadata solana", "token 2022 metadata"] ---- - -import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; -import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; -import MetadataAndMetadataPointerAiPrompt from "/snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx"; -import MetadataPointerAction from "/snippets/code-snippets/light-token/extensions/metadata-pointer/action.mdx"; - -MetadataPointer tells clients where to find a mint's metadata. TokenMetadata removes the need for a separate metadata account. - -## Key Parameters - -MetadataPointer and TokenMetadata are configured together with these parameters: - -| Parameter | Description | -|-----------|-------------| -| `authority` | Account authorized to update the metadata pointer address. | -| `metadataAddress` | Account where metadata is stored. Set to the mint itself to keep metadata on-chain in a single account. | -| `updateAuthority` | Account that can modify token metadata fields after initialization. | -| `name` | Human-readable token name (e.g., "Example Token"). | -| `symbol` | Short token symbol (e.g., "EXT"). | -| `uri` | URL pointing to an external JSON file with extended metadata. | -| `additionalMetadata` | Key-value pairs for custom descriptive fields. | - -When the MetadataPointer points to the mint itself, TokenMetadata stores name, symbol, URI, and additional fields directly in the mint account data. This produces a self-describing token in a single account. - -Both extensions work without restrictions in Light Token. - -## Use MetadataPointer and TokenMetadata With Light Token - - - - - - - - -### Create a Token-2022 Mint With Metadata - - - - -```typescript -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - getMintLen, - createInitializeMint2Instruction, - ExtensionType, - createInitializeMetadataPointerInstruction, -} from "@solana/spl-token"; -import { - createInitializeInstruction as createInitializeTokenMetadataInstruction, - pack, - TokenMetadata, -} from "@solana/spl-token-metadata"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const decimals = 9; - -const metadata: TokenMetadata = { - mint: mintKeypair.publicKey, - name: "Example Token", - symbol: "EXT", - uri: "https://example.com/metadata.json", - additionalMetadata: [], -}; - -// Calculate space for mint + MetadataPointer extension -const mintLen = getMintLen([ExtensionType.MetadataPointer]); -const metadataLen = pack(metadata).length; -const totalLen = mintLen + metadataLen; -const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(totalLen); - -// Create account -const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, -}); - -// Initialize MetadataPointer (points to the mint itself) -const initMetadataPointerIx = createInitializeMetadataPointerInstruction( - mintKeypair.publicKey, - payer.publicKey, - mintKeypair.publicKey, // metadata address = mint itself - TOKEN_2022_PROGRAM_ID -); - -// Initialize mint -const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, - null, - TOKEN_2022_PROGRAM_ID -); - -// Initialize TokenMetadata on the mint -const initTokenMetadataIx = createInitializeTokenMetadataInstruction({ - programId: TOKEN_2022_PROGRAM_ID, - mint: mintKeypair.publicKey, - metadata: mintKeypair.publicKey, - mintAuthority: payer.publicKey, - name: metadata.name, - symbol: metadata.symbol, - uri: metadata.uri, - updateAuthority: payer.publicKey, -}); - -// Register interface PDA with Light Token -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); - -const tx = new Transaction().add( - createAccountIx, - initMetadataPointerIx, - initMintIx, - initTokenMetadataIx, - createSplInterfaceIx -); - -const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, -]); -``` - - - - - - -`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the MetadataPointer and TokenMetadata extensions, use the instruction approach shown in the other tab. - - - - - -### Create Interface PDA for Existing Mint - -If you already have a Token-2022 mint with MetadataPointer and TokenMetadata, create an interface PDA with Light Token. - -```typescript -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); -``` - - - - - - - -## Related Guides - - - - - - - diff --git a/light-token/extensions/overview.mdx b/light-token/extensions/overview.mdx index e87780e..35565bd 100644 --- a/light-token/extensions/overview.mdx +++ b/light-token/extensions/overview.mdx @@ -1,42 +1,26 @@ --- -title: "Token extensions" -sidebarTitle: "Overview" +title: "Token 2022 Extensions with Light Token" +sidebarTitle: "Extensions" description: "Most Token 2022 extensions are supported by Light Token to add features through extra instructions to a token mint or token account." keywords: ["token 2022 extensions light token", "token extensions solana", "metadata pointer light token", "transfer fee config light token", "confidential transfers light token"] --- import SupportFooter from "/snippets/support-footer.mdx"; +import ExtensionsTable from "/snippets/extensions-table.mdx"; ## How extensions work with Light Token 1. **Create** a Token-2022 mint with one or more extensions -2. **Register** an interface PDA to hold balances from that mint in Light Token accounts +2. **[Register an interface PDA](/light-token/cookbook/add-interface-pda)** to hold balances from that mint in Light Token accounts 3. **Use** the same Light Token APIs (`transferInterface`, `wrap`, `unwrap`) as any other token Each extension adds specific state that's generally initialized during mint or token account creation. When initializing either account, you can enable specific extensions simultaneously for different functionality. -Most extensions can't be added after an account is initialized. +Most extensions can't be added after an account is initialized. Use the Solana documentation to learn more about Token 2022 extensions. ## Supported extensions -| Extension | Restriction | Description | -|-----------|-------------|-------------| -| [MetadataPointer](/light-token/extensions/metadata-and-metadata-pointer) | - | Points a mint to the account that stores its metadata. | -| [TokenMetadata](/light-token/extensions/metadata-and-metadata-pointer) | - | Stores token name, symbol, and URI directly on the mint. | -| [TransferFeeConfig](/light-token/extensions/transfer-fees) | Fees must be zero | Withholds a percentage of each transfer as a fee. | -| [TransferHook](/light-token/extensions/transfer-hook) | `program_id` must be nil | Invokes a custom program on every transfer via CPI. | -| [InterestBearingConfig](/light-token/extensions/interest-bearing-tokens) | - | Displays a UI-adjusted balance that accrues interest over time. | -| [DefaultAccountState](/light-token/extensions/default-account-state) | No compressed transfer | Sets the initial state (e.g., frozen) for newly created token accounts. | -| [PermanentDelegate](/light-token/extensions/permanent-delegate) | No compressed transfer | Grants an authority unrestricted transfer and burn rights over all accounts for the mint. | -| [MintCloseAuthority](/light-token/extensions/close-mint) | No compressed transfer | Allows a designated authority to close a mint account. | -| [GroupPointer](/light-token/extensions/token-groups-and-members) | - | Points a mint to the account that stores group configuration. | -| [GroupMemberPointer](/light-token/extensions/token-groups-and-members) | - | Points a mint to the account that stores group member configuration. | -| [TokenGroup](/light-token/extensions/token-groups-and-members) | - | Stores group configuration directly on the mint (e.g., NFT collections). | -| [TokenGroupMember](/light-token/extensions/token-groups-and-members) | - | Stores group member configuration directly on the mint. | -| [Pausable](/light-token/extensions/pausable-mint) | No compressed transfer | Allows an authority to pause all minting, burning, and transfers. | -| [ConfidentialTransferMint](/light-token/extensions/confidential-transfer) | Initialized but not enabled | Configures auditor keys for confidential (encrypted) transfers. | -| [ConfidentialTransferFeeConfig](/light-token/extensions/confidential-transfer) | Fees must be zero | Encrypts withheld transfer fees under an auditor's public key. | -| [ConfidentialMintBurn](/light-token/extensions/confidential-transfer) | Initialized but not enabled | Allows minting and burning of tokens with encrypted amounts. | + ## Not supported diff --git a/light-token/extensions/pausable-mint.mdx b/light-token/extensions/pausable-mint.mdx deleted file mode 100644 index d9c20a7..0000000 --- a/light-token/extensions/pausable-mint.mdx +++ /dev/null @@ -1,156 +0,0 @@ ---- -title: "Pausable mint" -sidebarTitle: "Pausable mint" -description: "Configure the Pausable extension to pause and resume all minting, burning, and transfers for a Token-2022 mint using Light Token." -keywords: ["pausable light token", "pausable solana", "token 2022 pausable"] ---- - -import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; -import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; -import PausableMintAiPrompt from "/snippets/ai-prompts/extensions/pausable-mint.mdx"; -import PausableAction from "/snippets/code-snippets/light-token/extensions/pausable/action.mdx"; - -When paused, all minting, burning, and transfers are blocked until the authority resumes the mint. - - -Set the `compression_only` flag when creating token accounts for this mint. Use `transferInterface` for transfers as usual. - - -## Key Parameters - -Pausable is configured with two parameters: - -| Parameter | Description | -|-----------|-------------| -| `authority` | The public key authorized to pause and resume the mint. | -| `paused` | Boolean flag indicating the current pause state. Initialized as `false`. | - -When paused, the Token-2022 program rejects all transfers, mints, and burns for the token. The pause authority can resume operations at any time. - -## Use Pausable With Light Token - - - - - - - - -### Create a Token-2022 Mint With Pausable - - - - -```typescript -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - ExtensionType, - getMintLen, - createInitializeMint2Instruction, - createInitializePausableConfigInstruction, -} from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const decimals = 9; - -// Calculate space for mint + Pausable extension -const mintLen = getMintLen([ExtensionType.PausableConfig]); -const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - -// Create account -const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, -}); - -// Initialize Pausable extension -const initPausableIx = createInitializePausableConfigInstruction( - mintKeypair.publicKey, - payer.publicKey, // pause authority - TOKEN_2022_PROGRAM_ID, -); - -// Initialize mint -const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID, -); - -// Register interface PDA with Light Token -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); - -const tx = new Transaction().add( - createAccountIx, - initPausableIx, - initMintIx, - createSplInterfaceIx -); - -const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, -]); -``` - - - - - - -`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the Pausable extension, use the instruction approach shown in the other tab. - - - - - -### Create Interface PDA for Existing Mint - -If you already have a Token-2022 mint with Pausable, create an interface PDA with Light Token. - -```typescript -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); -``` - - - - - - - -## Related Guides - - - - - - - diff --git a/light-token/extensions/permanent-delegate.mdx b/light-token/extensions/permanent-delegate.mdx deleted file mode 100644 index 73bc6d7..0000000 --- a/light-token/extensions/permanent-delegate.mdx +++ /dev/null @@ -1,155 +0,0 @@ ---- -title: "Permanent delegate" -sidebarTitle: "Permanent delegate" -description: "Configure the PermanentDelegate extension to grant irrevocable transfer and burn authority over all token accounts using Light Token." -keywords: ["permanent delegate light token", "permanent delegate solana", "token 2022 permanent delegate"] ---- - -import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; -import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; -import PermanentDelegateAiPrompt from "/snippets/ai-prompts/extensions/permanent-delegate.mdx"; -import PermanentDelegateAction from "/snippets/code-snippets/light-token/extensions/permanent-delegate/action.mdx"; - -A designated authority gains irrevocable transfer and burn rights over every token account for a mint, set once at initialization and enforced permanently. - - -Set the `compression_only` flag when creating token accounts for this mint. Use `transferInterface` for transfers as usual. - - -## Key Parameters - -PermanentDelegate is configured with one parameter: - -| Parameter | Description | -|-----------|-------------| -| `delegate` | The public key granted permanent, irrevocable transfer and burn authority over all token accounts for this mint. | - -Unlike standard delegates set per token account, the permanent delegate operates at the mint level. Token account owners cannot revoke this authority. Only the current permanent delegate can reassign the role to a new account. - -## Use PermanentDelegate With Light Token - - - - - - - - -### Create a Token-2022 Mint With Permanent Delegate - - - - -```typescript -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - ExtensionType, - getMintLen, - createInitializeMint2Instruction, - createInitializePermanentDelegateInstruction, -} from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const decimals = 9; - -// Calculate space for mint + PermanentDelegate extension -const mintLen = getMintLen([ExtensionType.PermanentDelegate]); -const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - -// Create account -const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, -}); - -// Initialize PermanentDelegate extension -const initPermanentDelegateIx = createInitializePermanentDelegateInstruction( - mintKeypair.publicKey, - payer.publicKey, // permanent delegate authority - TOKEN_2022_PROGRAM_ID, -); - -// Initialize mint -const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID, -); - -// Register interface PDA with Light Token -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); - -const tx = new Transaction().add( - createAccountIx, - initPermanentDelegateIx, - initMintIx, - createSplInterfaceIx -); - -const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, -]); -``` - - - - - - -`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the PermanentDelegate extension, use the instruction approach shown in the other tab. - - - - - -### Create Interface PDA for Existing Mint - -If you already have a Token-2022 mint with PermanentDelegate, create an interface PDA with Light Token. - -```typescript -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); -``` - - - - - - - -## Related Guides - - - - - - - diff --git a/light-token/extensions/token-groups-and-members.mdx b/light-token/extensions/token-groups-and-members.mdx deleted file mode 100644 index 4962572..0000000 --- a/light-token/extensions/token-groups-and-members.mdx +++ /dev/null @@ -1,217 +0,0 @@ ---- -title: "Token groups and members" -sidebarTitle: "Token groups and members" -description: "Configure the GroupPointer, TokenGroup, GroupMemberPointer, and TokenGroupMember extensions to organize tokens into collections using Light Token." -keywords: ["token groups light token", "token groups solana", "token 2022 token groups", "nft collections solana"] ---- - -import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; -import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; -import TokenGroupsAndMembersAiPrompt from "/snippets/ai-prompts/extensions/token-groups-and-members.mdx"; - -Organize tokens into hierarchical groups such as NFT collections by linking a group mint to one or more member mints through on-chain pointer and data extensions. - -## Key Parameters - -Token groups use four related extensions that work in pairs: - -| Extension | Parameters | Description | -|-----------|------------|-------------| -| `GroupPointer` | `authority`, `groupAddress` | Designates a mint as a group mint by pointing to an account that stores group configuration. Typically points to the mint itself. | -| `TokenGroup` | `updateAuthority`, `mint`, `size`, `maxSize` | Stores the group metadata (update authority, current member count, maximum size) directly on the mint account. | -| `GroupMemberPointer` | `authority`, `memberAddress` | Designates a mint as a member mint by pointing to an account that stores membership data. Typically points to the mint itself. | -| `TokenGroupMember` | `mint`, `group`, `memberNumber` | Stores the membership data (parent group address, sequential member number) directly on the mint account. | - -## Use Token Groups With Light Token - - - - - - - - -### Create Group Mint - -Create a Token-2022 mint with the GroupPointer and TokenGroup extensions. - -```typescript -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - ExtensionType, - getMintLen, - createInitializeMint2Instruction, - createInitializeGroupPointerInstruction, - createInitializeGroupInstruction, -} from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const groupMintKeypair = Keypair.generate(); -const decimals = 0; - -// Calculate space including GroupPointer and TokenGroup extensions -const mintLen = getMintLen([ExtensionType.GroupPointer, ExtensionType.TokenGroup]); -const rentExemptBalance = await rpc.getMinimumBalanceForRentExemption(mintLen); - -// Create the mint account -const createMintAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: groupMintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, -}); - -// Initialize GroupPointer (points to the mint itself) -const initGroupPointerIx = createInitializeGroupPointerInstruction( - groupMintKeypair.publicKey, - payer.publicKey, // authority - groupMintKeypair.publicKey, // group address (self-referencing) - TOKEN_2022_PROGRAM_ID, -); - -// Initialize the mint -const initMintIx = createInitializeMint2Instruction( - groupMintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID, -); - -// Initialize the TokenGroup data on the mint -const initGroupIx = createInitializeGroupInstruction({ - group: groupMintKeypair.publicKey, - maxSize: 100, - mint: groupMintKeypair.publicKey, - mintAuthority: payer.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - updateAuthority: payer.publicKey, -}); - -const tx = new Transaction().add( - createMintAccountIx, - initGroupPointerIx, - initMintIx, - initGroupIx, -); - -const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - groupMintKeypair, -]); -``` - -### Create Member Mint - -Create a member mint with the GroupMemberPointer and TokenGroupMember extensions, linking it to the group mint. - -```typescript -import { - createInitializeGroupMemberPointerInstruction, - createInitializeMemberInstruction, -} from "@solana/spl-token"; - -const memberMintKeypair = Keypair.generate(); - -// Calculate space including GroupMemberPointer and TokenGroupMember extensions -const memberMintLen = getMintLen([ - ExtensionType.GroupMemberPointer, - ExtensionType.TokenGroupMember, -]); -const memberRentExemptBalance = await rpc.getMinimumBalanceForRentExemption(memberMintLen); - -// Create the member mint account -const createMemberMintIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: memberRentExemptBalance, - newAccountPubkey: memberMintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: memberMintLen, -}); - -// Initialize GroupMemberPointer (points to the member mint itself) -const initMemberPointerIx = createInitializeGroupMemberPointerInstruction( - memberMintKeypair.publicKey, - payer.publicKey, // authority - memberMintKeypair.publicKey, // member address (self-referencing) - TOKEN_2022_PROGRAM_ID, -); - -// Initialize the member mint -const initMemberMintIx = createInitializeMint2Instruction( - memberMintKeypair.publicKey, - 0, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID, -); - -// Initialize the TokenGroupMember data on the member mint -const initMemberIx = createInitializeMemberInstruction({ - group: groupMintKeypair.publicKey, - groupUpdateAuthority: payer.publicKey, - member: memberMintKeypair.publicKey, - memberMint: memberMintKeypair.publicKey, - memberMintAuthority: payer.publicKey, - programId: TOKEN_2022_PROGRAM_ID, -}); - -const memberTx = new Transaction().add( - createMemberMintIx, - initMemberPointerIx, - initMemberMintIx, - initMemberIx, -); - -await sendAndConfirmTransaction(rpc, memberTx, [payer, memberMintKeypair]); -``` - -### Create Interface PDA for Existing Mints - -Create interface PDAs for both the group mint and member mint with Light Token. - -```typescript -// Register group mint -const registerGroupIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: groupMintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); - -// Register member mint -const registerMemberIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: memberMintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); - -const registerTx = new Transaction().add(registerGroupIx, registerMemberIx); -await sendAndConfirmTransaction(rpc, registerTx, [payer]); -``` - - - - - - - - -## Related Guides - - - - - - - diff --git a/light-token/extensions/transfer-fees.mdx b/light-token/extensions/transfer-fees.mdx deleted file mode 100644 index 9cf89bb..0000000 --- a/light-token/extensions/transfer-fees.mdx +++ /dev/null @@ -1,156 +0,0 @@ ---- -title: "Transfer fees" -sidebarTitle: "Transfer fees" -description: "Configure the TransferFeeConfig extension for automatic fee collection on every token transfer using Light Token." -keywords: ["transfer fees light token", "transfer fees solana", "token 2022 transfer fees"] ---- - -import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; -import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; -import TransferFeesAiPrompt from "/snippets/ai-prompts/extensions/transfer-fees.mdx"; -import TransferFeeAction from "/snippets/code-snippets/light-token/extensions/transfer-fees/action.mdx"; - -## Key Concepts - -The TransferFeeExtension enables automatic fee collection on every token transfer. -Fees accumulate in the recipient token accounts and can be withdrawn by the withdraw authority set on the mint account. - -Transfer fees are configured with four parameters: - -| Parameter | Description | -|-----------|-------------| -| `transferFeeBasisPoints` | Fee percentage in basis points (100 = 1%). **Must be zero for Light Token.** | -| `maximumFee` | Upper limit on the fee charged per transfer, in token base units. **Must be zero for Light Token.** | -| `transferFeeConfigAuthority` | Authority that can modify fee settings. | -| `withdrawWithheldAuthority` | Authority that can collect accumulated fees from recipient accounts. | - -## Use TransferFeeConfig With Light Token - - - - - - - - -### Create a Token-2022 Mint With Transfer Fees - - - - -```typescript -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - getMintLen, - createInitializeMint2Instruction, - ExtensionType, - createInitializeTransferFeeConfigInstruction, -} from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const decimals = 9; - -// Calculate space for mint + TransferFeeConfig extension -const mintLen = getMintLen([ExtensionType.TransferFeeConfig]); -const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - -// Create account -const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, -}); - -// Initialize TransferFeeConfig with zero fees -const initTransferFeeIx = createInitializeTransferFeeConfigInstruction( - mintKeypair.publicKey, - payer.publicKey, // transfer fee config authority - payer.publicKey, // withdraw withheld authority - 0, // fee basis points (must be zero) - BigInt(0), // maximum fee (must be zero) - TOKEN_2022_PROGRAM_ID -); - -// Initialize mint -const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, - null, - TOKEN_2022_PROGRAM_ID -); - -// Register interface PDA with Light Token -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); - -const tx = new Transaction().add( - createAccountIx, - initTransferFeeIx, - initMintIx, - createSplInterfaceIx -); - -const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, -]); -``` - - - - - - -`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the TransferFeeConfig extension, use the instruction approach shown in the other tab. - - - - - -### Create Interface PDA for Existing Mint - -If you already have a Token-2022 mint with a zero-fee TransferFeeConfig, create an interface PDA with Light Token. - -```typescript -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); -``` - - - - - - - -## Related Guides - - - - - - - diff --git a/light-token/extensions/transfer-hook.mdx b/light-token/extensions/transfer-hook.mdx deleted file mode 100644 index 2c7edff..0000000 --- a/light-token/extensions/transfer-hook.mdx +++ /dev/null @@ -1,158 +0,0 @@ ---- -title: "Transfer hook" -sidebarTitle: "Transfer hook" -description: "Configure the TransferHook extension to attach a custom program callback to every token transfer using Light Token." -keywords: ["transfer hook light token", "transfer hook solana", "token 2022 transfer hook"] ---- - -import ExtensionsSetup from "/snippets/setup/extensions-setup.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; -import AgentSkillGeneric from "/snippets/setup/agent-skill-generic.mdx"; -import TransferHookAiPrompt from "/snippets/ai-prompts/extensions/transfer-hook.mdx"; -import TransferHookAction from "/snippets/code-snippets/light-token/extensions/transfer-hook/action.mdx"; - - -## Key Parameters - -A program address stored on the mint is invoked via CPI on every token transfer to execute custom logic -such as transfer restrictions, royalty enforcement, or event emission. - -TransferHook is configured with two parameters: - -| Parameter | Description | -|-----------|-------------| -| `authority` | Account that can update the transfer hook program address after initialization. | -| `programId` | Address of the program invoked via CPI on every transfer. **Must be `PublicKey.default` (nil) for Light Token.** | - - -Light Token requires the TransferHook `program_id` to be set to `PublicKey.default` (all zeros). You can initialize the extension for compatibility, but active hooks are not supported. Registration fails if the `program_id` points to a real program. - - -## Use TransferHook With Light Token - - - - - - - - -### Create a Token-2022 Mint With Transfer Hook - - - - -```typescript -import { - Keypair, - PublicKey, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - getMintLen, - createInitializeMint2Instruction, - ExtensionType, - createInitializeTransferHookInstruction, -} from "@solana/spl-token"; - -const rpc = createRpc(RPC_ENDPOINT); - -const mintKeypair = Keypair.generate(); -const decimals = 9; - -// Calculate space for mint + TransferHook extension -const mintLen = getMintLen([ExtensionType.TransferHook]); -const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - -// Create account -const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, -}); - -// Initialize TransferHook with nil program_id (hook disabled) -const initTransferHookIx = createInitializeTransferHookInstruction( - mintKeypair.publicKey, - payer.publicKey, // authority - PublicKey.default, // program_id must be nil - TOKEN_2022_PROGRAM_ID -); - -// Initialize mint -const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, - null, - TOKEN_2022_PROGRAM_ID -); - -// Register interface PDA with Light Token -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); - -const tx = new Transaction().add( - createAccountIx, - initTransferHookIx, - initMintIx, - createSplInterfaceIx -); - -const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, -]); -``` - - - - - - -`createMintInterface` creates a basic Token 2022 mint with an interface PDA. To include the TransferHook extension, use the instruction approach shown in the other tab. - - - - - -### Create Interface PDA for Existing Mint - -If you already have a Token-2022 mint with TransferHook set to a nil `program_id`, create an interface PDA with Light Token. - -```typescript -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; - -const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, -}); -``` - - - - - - - -## Related Guides - - - - - - - diff --git a/light-token/payments/overview.mdx b/light-token/payments/overview.mdx index 83c5127..9055758 100644 --- a/light-token/payments/overview.mdx +++ b/light-token/payments/overview.mdx @@ -20,7 +20,6 @@ import { } from "/snippets/code-samples/code-compare-snippets.jsx"; import SupportFooter from "/snippets/support-footer.mdx"; import RentSponsorship from "/snippets/rent-sponsorship-explained.mdx"; -import ExtensionsTable from "/snippets/extensions-table.mdx"; Payment flows on Solana include five core concepts: @@ -62,21 +61,40 @@ For example, here is the creation of an associated token account: secondLabel="SPL" /> +## Interoperability + + +The Light Token APIs cover every SPL Token operation and adds extra capabilities: + + + + + + + + + + + + + + + + + + + + + + +
CategoryWhat it does
**Cross-program dispatch**`Interface` methods (e.g., `transferInterface`) auto-detect the token program and dispatch to SPL, Token 2022, or Light Token.
**Unified balance**`getAtaInterface` returns a unified balance for a given mint held in Light Token accounts. With `wrap=true`, it also includes SPL and Token 2022 balances.
**Wrap / Unwrap**For interoperability with applications that don't support Light Token yet, you can wrap / unwrap SPL or Token 2022 tokens into Light Token associated token accounts and back.
+ ## Token Extensions Token extensions introduce optional features you can add to a token mint or token account through -extra instructions. - - - - - - +extra instructions. Light Token supports most Token 2022 extensions. - -Learn more about Token-2022 extensions: [Extensions](https://solana.com/docs/tokens/extensions). - - + ## Start Integrating diff --git a/light-token/payments/spend-permissions.mdx b/light-token/payments/spend-permissions.mdx index 09ecc9a..34d2dc2 100644 --- a/light-token/payments/spend-permissions.mdx +++ b/light-token/payments/spend-permissions.mdx @@ -37,7 +37,7 @@ When you approve a delegate, you're authorizing a specific account to transfer t **Delegated Transfer** transfer() (delegate signs) - transferDelegatedInterface() + transferInterface({ owner }) **Revoke** @@ -108,20 +108,22 @@ console.log("Delegated amount:", account.parsed.delegatedAmount.toString()); Once approved, the delegate can transfer tokens on behalf of the owner. The delegate is the transaction authority. Only the delegate and fee payer sign; the owner's signature is not required. -`transferDelegatedInterface` takes a recipient wallet address and creates the recipient's associated token account internally. +`transferInterface` takes a recipient wallet address and creates the recipient's associated token account internally. Pass `{ owner }` to transfer as a delegate instead of the owner. ```typescript -import { transferDelegatedInterface } from "@lightprotocol/compressed-token/unified"; +import { transferInterface } from "@lightprotocol/compressed-token/unified"; -const tx = await transferDelegatedInterface( +const tx = await transferInterface( rpc, payer, senderAta, mint, recipient.publicKey, // recipient wallet (associated token account created internally) delegate, // delegate authority (signer) - owner.publicKey, // owner (does not sign) 200_000, // must be within approved cap + undefined, + undefined, + { owner: owner.publicKey } // owner (does not sign) ); console.log("Delegated transfer:", tx); @@ -129,24 +131,24 @@ console.log("Delegated transfer:", tx); -`createTransferDelegatedInterfaceInstructions` returns `TransactionInstruction[][]` for manual transaction control. +`createTransferInterfaceInstructions` returns `TransactionInstruction[][]` for manual transaction control. Pass `owner` to transfer as a delegate. ```typescript import { Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; -import { createTransferDelegatedInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; -const instructions = await createTransferDelegatedInterfaceInstructions( +const instructions = await createTransferInterfaceInstructions( rpc, payer.publicKey, mint, 200_000, delegate.publicKey, - owner.publicKey, recipient.publicKey, 9, // decimals + { owner: owner.publicKey } ); for (const ixs of instructions) { diff --git a/light-token/payments/verify-payments.mdx b/light-token/payments/verify-payments.mdx index 2c66e04..fc6d6c6 100644 --- a/light-token/payments/verify-payments.mdx +++ b/light-token/payments/verify-payments.mdx @@ -49,6 +49,10 @@ const rpc = createRpc(RPC_ENDPOINT); ## Query balance +### Light Token balance + +Returns the Light Token ATA balance (hot balance). + Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-balance.ts). @@ -62,7 +66,7 @@ import { const ata = getAssociatedTokenAddressInterface(mint, owner); const account = await getAtaInterface(rpc, ata, owner, mint); -console.log(account.parsed.amount); +console.log(account.parsed.amount); // Light Token ATA balance ``` @@ -77,6 +81,30 @@ console.log(account.amount); +### Unified balance + +To include compressed (cold) and optionally SPL/T22 balances, call `loadAta` first to unify everything into the Light Token ATA, then read the balance. + +```typescript +import { + loadAta, + getAssociatedTokenAddressInterface, + getAtaInterface, +} from "@lightprotocol/compressed-token/unified"; + +const ata = getAssociatedTokenAddressInterface(mint, owner); + +// Unify compressed (cold) balances into the Light Token ATA +await loadAta(rpc, ata, payer, mint, payer); + +const account = await getAtaInterface(rpc, ata, owner, mint); +console.log(account.parsed.amount); // Unified balance +``` + + +See the [Load Associated Token Account](/light-token/cookbook/load-ata) guide for details on `loadAta`, including wrapping SPL and Token 2022 balances. + + ## Transaction history diff --git a/light-token/payments/verify-recipient-address.mdx b/light-token/payments/verify-recipient-address.mdx index 4a4358e..fdde7e3 100644 --- a/light-token/payments/verify-recipient-address.mdx +++ b/light-token/payments/verify-recipient-address.mdx @@ -39,7 +39,7 @@ import PaymentsAiPrompt from "/snippets/ai-prompts/toolkits/payments.mdx"; Solana has two types of addresses: - **On-curve addresses** (wallets): derived from a keypair, can sign transactions. -- **Off-curve addresses** (PDAs): program-derived addresses, can only sign via CPI when used as [smart wallets](/light-token/wallets/smart-wallets). +- **Off-curve addresses** (PDAs): program-derived addresses, can only sign via CPI. ## Verification flow diff --git a/light-token/wallets/overview.mdx b/light-token/wallets/overview.mdx index 5f87cff..f90fea7 100644 --- a/light-token/wallets/overview.mdx +++ b/light-token/wallets/overview.mdx @@ -451,8 +451,6 @@ await unwrap(rpc, payer, splAta, owner, mint, amount); - - diff --git a/light-token/wallets/smart-wallets.mdx b/light-token/wallets/smart-wallets.mdx deleted file mode 100644 index c604f96..0000000 --- a/light-token/wallets/smart-wallets.mdx +++ /dev/null @@ -1,340 +0,0 @@ ---- -title: "Smart Wallets" -sidebarTitle: "Using Smart Wallets" -description: "Send Light Tokens from PDA-based smart wallets. Covers off-curve associated token account creation, instruction-level transfers, and sync and async execution with Squads." -keywords: ["smart wallets solana", "squads multisig light token", "PDA wallet token transfer", "off-curve ATA solana", "rent-free tokens smart wallet"] ---- - -import SmartWalletsAiPrompt from "/snippets/ai-prompts/wallets/smart-wallets.mdx"; -import SupportFooter from "/snippets/support-footer.mdx"; - ---- - -A smart wallet is a program deployed on-chain that provides secure, programmable wallet infrastructure. -The signer is separate from the wallet and can be anything: passkeys, AWS KMS, MPC, or a multisig threshold. - -When a PDA owns tokens instead of a keypair, two things change: - -| | Standard wallet | Smart wallet (PDA) | -|:------|:----------------|:-------------------| -| **Create associated token account** | `createAtaInterface(rpc, payer, mint, owner)` | `createAtaInterface(rpc, payer, mint, walletPda, true)` | -| **Transfer** | `transferInterface(...)` or `createTransferInterfaceInstructions(...)` | `createLightTokenTransferInstruction(...)` | -| **Signing** | Keypair signs directly | Smart wallet program signs via CPI | - -`transferInterface` rejects off-curve addresses. Use `createLightTokenTransferInstruction` instead. It accepts any `PublicKey`, including PDAs. Pass `allowOwnerOffCurve=true` (5th argument) when creating the associated token account. - -This pattern applies to any PDA-based wallet program. The examples below use [Squads Smart Accounts](https://squads.so). - - -The [full example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/smart-wallet) includes wallet creation, funding, sync transfer, and async governance flow with an integration test. - - - - - -## Prerequisites - -You need an existing smart wallet (PDA) and a ZK Compression-compatible RPC endpoint. - -```bash -npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @sqds/smart-account -``` - -```typescript -import { createRpc } from "@lightprotocol/stateless.js"; -import { - createAtaInterface, - getAssociatedTokenAddressInterface, - createLightTokenTransferInstruction, -} from "@lightprotocol/compressed-token"; -import * as smartAccount from "@sqds/smart-account"; - -// Use a ZK Compression endpoint (Helius, Triton, or self-hosted) -const rpc = createRpc(RPC_ENDPOINT); -``` - - - -If you don't have a smart wallet yet, create one with Squads. Set `timeLock: 0` for sync execution, or a positive value to require async governance. - -```typescript -const programConfig = - await smartAccount.accounts.ProgramConfig.fromAccountAddress( - rpc, - smartAccount.getProgramConfigPda({})[0] - ); -const accountIndex = - BigInt(programConfig.smartAccountIndex.toString()) + 1n; -const [settingsPda] = smartAccount.getSettingsPda({ accountIndex }); - -await smartAccount.rpc.createSmartAccount({ - connection: rpc, - treasury: programConfig.treasury, - creator: payer, - settings: settingsPda, - settingsAuthority: null, - threshold: 1, - signers: [ - { - key: payer.publicKey, - permissions: smartAccount.types.Permissions.all(), - }, - ], - timeLock: 0, - rentCollector: null, - sendOptions: { skipPreflight: true }, -}); -``` - - - -Snippets below assume `rpc`, `payer`, `mint`, `settingsPda`, and `walletPda` are defined. See the [full example](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/smart-wallet) for runnable setup. - -## Create the wallet's token account - - - - - -The wallet PDA is derived by the smart wallet program. It is off-curve and cannot be used as a keypair. - -```typescript -const [walletPda] = smartAccount.getSmartAccountPda({ - settingsPda, - accountIndex: 0, -}); -``` - - - - - -Pass `true` as the 5th argument to allow the off-curve PDA as the token account owner: - -```typescript -await createAtaInterface(rpc, payer, mint, walletPda, true); -const walletAta = getAssociatedTokenAddressInterface(mint, walletPda, true); -``` - - - - - -## Fund the wallet - -Anyone can send Light Tokens to the wallet's associated token account. No smart wallet approval is needed. You can use `transferInterface` or `createLightTokenTransferInstruction` from any standard wallet: - -```typescript -const ix = createLightTokenTransferInstruction( - payerAta, // source - walletAta, // destination (the smart wallet's associated token account) - payer.publicKey, // owner of the source - amount // fee payer defaults to owner when omitted -); -``` - -The wallet PDA also needs SOL for inner transaction fees. Around 0.01 SOL is sufficient for many transfers: - -```typescript -import { SystemProgram } from "@solana/web3.js"; - -const fundIx = SystemProgram.transfer({ - fromPubkey: payer.publicKey, - toPubkey: walletPda, - lamports: 10_000_000, // 0.01 SOL -}); -``` - -## Send tokens from a smart wallet - - - - - -Use `createLightTokenTransferInstruction` to build the inner instruction. The wallet PDA is the owner. The optional 5th argument sets who pays rent top-ups. Pass `walletPda` so the wallet covers its own top-ups: - -```typescript -const transferIx = createLightTokenTransferInstruction( - walletAta, // source: wallet's Light Token associated token account - recipientAta, // destination - walletPda, // owner: the smart wallet PDA (off-curve) - amount, - walletPda // fee payer for rent top-ups (optional, defaults to owner) -); -``` - - - - - -The smart wallet program wraps your instruction and signs via CPI using the wallet PDA's seeds. - -Use **sync** when all signers are available and `timeLock=0`. The transfer happens in a single transaction. Use **async** when you need multi-party governance (threshold > 1 or time lock). - - - - -```typescript -import { - TransactionMessage, - VersionedTransaction, -} from "@solana/web3.js"; - -// Compile the inner instruction for synchronous execution -const { instructions, accounts } = - smartAccount.utils.instructionsToSynchronousTransactionDetails({ - vaultPda: walletPda, - members: [payer.publicKey], - transaction_instructions: [transferIx], - }); - -const syncIx = smartAccount.instructions.executeTransactionSync({ - settingsPda, - numSigners: 1, - accountIndex: 0, - instructions, - instruction_accounts: accounts, -}); - -// Send as a single transaction -const { blockhash } = await rpc.getLatestBlockhash(); -const msg = new TransactionMessage({ - payerKey: payer.publicKey, - recentBlockhash: blockhash, - instructions: [syncIx], -}).compileToV0Message(); - -const tx = new VersionedTransaction(msg); -tx.sign([payer]); -const sig = await rpc.sendRawTransaction(tx.serialize(), { - skipPreflight: true, -}); -await rpc.confirmTransaction(sig, "confirmed"); -``` - - - - -Each step is a separate transaction. This works with any threshold or time lock. - -```typescript -import { TransactionMessage } from "@solana/web3.js"; - -// Read the current transaction index -const settings = await smartAccount.accounts.Settings.fromAccountAddress( - rpc, - settingsPda -); -const txIndex = BigInt(settings.transactionIndex.toString()) + 1n; -const { blockhash } = await rpc.getLatestBlockhash(); - -// 1. Create the transaction -await smartAccount.rpc.createTransaction({ - connection: rpc, - feePayer: payer, - settingsPda, - transactionIndex: txIndex, - creator: payer.publicKey, - accountIndex: 0, - ephemeralSigners: 0, - transactionMessage: new TransactionMessage({ - payerKey: walletPda, - recentBlockhash: blockhash, - instructions: [transferIx], - }), - sendOptions: { skipPreflight: true }, -}); - -// 2. Create a proposal -await smartAccount.rpc.createProposal({ - connection: rpc, - feePayer: payer, - settingsPda, - transactionIndex: txIndex, - creator: payer, - sendOptions: { skipPreflight: true }, -}); - -// 3. Approve (repeat for each signer up to threshold) -await smartAccount.rpc.approveProposal({ - connection: rpc, - feePayer: payer, - settingsPda, - transactionIndex: txIndex, - signer: payer, - sendOptions: { skipPreflight: true }, -}); - -// 4. Execute -await smartAccount.rpc.executeTransaction({ - connection: rpc, - feePayer: payer, - settingsPda, - transactionIndex: txIndex, - signer: payer.publicKey, - signers: [payer], - sendOptions: { skipPreflight: true }, -}); -``` - - - - - - - - -## Check balance - -Query the wallet's token balance like any other account: - -```typescript -import { getAtaInterface } from "@lightprotocol/compressed-token/unified"; - -const account = await getAtaInterface(rpc, walletAta, walletPda, mint); -console.log(account.parsed.amount); -``` - -## Combine with gasless transactions - -You can sponsor the outer transaction fee so that only the wallet PDA's SOL is used for inner fees (rent top-ups). Set your application as `feePayer` on the outer transaction and pass it as the first signer: - -```typescript -// Outer transaction: your server pays the Solana network fee -const msg = new TransactionMessage({ - payerKey: sponsor.publicKey, // sponsor pays outer tx fee - recentBlockhash: blockhash, - instructions: [syncIx], -}).compileToV0Message(); - -const tx = new VersionedTransaction(msg); -tx.sign([sponsor, payer]); // sponsor + smart wallet signer -``` - -See [Gasless transactions](/light-token/wallets/gasless-transactions) for the full pattern. - -## Further reading - -- [Solana Smart Wallets](https://www.helius.dev/blog/solana-smart-wallets) : background on smart wallet concepts and account abstraction on Solana - - - - - - - -## Related guides - - - - Send a single token transfer. - - - Sponsor fees so users never hold SOL. - - - Full wallet integration reference. - - - - diff --git a/llms.txt b/llms.txt index fd5a021..cb3224a 100644 --- a/llms.txt +++ b/llms.txt @@ -90,7 +90,6 @@ Comparing creation cost and CU usage: - [Sign with Privy](https://www.zkcompression.com/light-token/wallets/privy.md): Integrate light-token with Privy embedded wallets for rent-free token accounts and transfers. - [Sign with Wallet Adapter](https://www.zkcompression.com/light-token/wallets/wallet-adapter.md): Integrate light-token with Solana Wallet Adapter for rent-free token accounts and transfers. - [Gasless Transactions](https://www.zkcompression.com/light-token/wallets/gasless-transactions.md): Abstract SOL fees so users never hold SOL. The Light SDK sponsors rent-exemption for Solana accounts and keeps accounts active through periodic top-ups paid by the fee payer. Sponsor top-ups and transaction fees by setting your application as the fee payer. -- [Smart Wallets](https://www.zkcompression.com/light-token/wallets/smart-wallets.md): Send Light Tokens from PDA-based smart wallets. Covers off-curve associated token account creation, instruction-level transfers, and sync and async execution with Squads. ## For DeFi - [Router Integration](https://www.zkcompression.com/light-token/defi/routers.md): Add support for rent-free AMMs on Solana. @@ -117,17 +116,7 @@ Comparing creation cost and CU usage: - [Load Token Balances to Light Associated Token Account](https://www.zkcompression.com/light-token/cookbook/load-ata.md): Unify token balances from compressed tokens (cold Light Tokens), SPL, and Token 2022 to one light ATA. - [Close Light Token Account](https://www.zkcompression.com/light-token/cookbook/close-token-account.md): Program guide to close Light Token accounts via CPI. Includes step-by-step implementation and full code examples. - [Burn Light Tokens](https://www.zkcompression.com/light-token/cookbook/burn.md): Rust client guide to burn Light Tokens. Includes step-by-step implementation and full code examples. -- [Token extensions](https://www.zkcompression.com/light-token/extensions/overview.md): Most Token 2022 extensions are supported by Light Token to add features through extra instructions to a token mint or token account. -- [Metadata and metadata pointer](https://www.zkcompression.com/light-token/extensions/metadata-and-metadata-pointer.md): Configure the MetadataPointer and TokenMetadata extensions to store token name, symbol, and URI on a Token 2022 mint using Light Token. -- [Transfer fees](https://www.zkcompression.com/light-token/extensions/transfer-fees.md): Configure the TransferFeeConfig extension for automatic fee collection on every token transfer using Light Token. -- [Transfer hook](https://www.zkcompression.com/light-token/extensions/transfer-hook.md): Configure the TransferHook extension to attach a custom program callback to every token transfer using Light Token. -- [Interest bearing tokens](https://www.zkcompression.com/light-token/extensions/interest-bearing-tokens.md): Configure the InterestBearingConfig extension to display UI-adjusted balances that accrue interest over time using Light Token. -- [Default account state](https://www.zkcompression.com/light-token/extensions/default-account-state.md): Configure the DefaultAccountState extension to set the initial state for newly created token accounts using Light Token. -- [Permanent delegate](https://www.zkcompression.com/light-token/extensions/permanent-delegate.md): Configure the PermanentDelegate extension to grant irrevocable transfer and burn authority over all token accounts using Light Token. -- [Close mint](https://www.zkcompression.com/light-token/extensions/close-mint.md): Configure the MintCloseAuthority extension to allow closing a mint account and reclaiming rent using Light Token. -- [Token groups and members](https://www.zkcompression.com/light-token/extensions/token-groups-and-members.md): Configure the GroupPointer, TokenGroup, GroupMemberPointer, and TokenGroupMember extensions to organize tokens into collections using Light Token. -- [Pausable mint](https://www.zkcompression.com/light-token/extensions/pausable-mint.md): Configure the Pausable extension to pause and resume all minting, burning, and transfers for a Token-2022 mint using Light Token. -- [Confidential transfer](https://www.zkcompression.com/light-token/extensions/confidential-transfer.md): Configure the ConfidentialTransferMint, ConfidentialTransferFeeConfig, and ConfidentialMintBurn extensions for encrypted token amounts using Light Token. +- [Token 2022 Extensions with Light Token](https://www.zkcompression.com/light-token/extensions/overview.md): Most Token 2022 extensions are supported by Light Token to add features through extra instructions to a token mint or token account. - [Client examples](https://www.zkcompression.com/light-token/examples/client.md): TypeScript and Rust client examples for light-token SDK. - [Program examples](https://www.zkcompression.com/light-token/examples/program.md): Anchor program examples for light-token CPI. diff --git a/scripts/copy-extensions-snippets.sh b/scripts/copy-extensions-snippets.sh deleted file mode 100755 index d39e4c2..0000000 --- a/scripts/copy-extensions-snippets.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash - -# Script to copy TypeScript extension examples to docs snippets. -# Source: examples-light-token-main/extensions -# Output: snippets/code-snippets/light-token/extensions/{name}/action.mdx - -EXAMPLES="/home/tilo/Workspace/examples-light-token-main/extensions" -SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/light-token/extensions" - -# Mapping of source-filename:output-dir -EXTENSIONS=( - "close-mint:close-mint" - "confidential-transfer:confidential-transfer" - "default-account-state:default-account-state" - "interest-bearing-tokens:interest-bearing" - "metadata-and-metadata-pointer:metadata-pointer" - "pausable-mint:pausable" - "permanent-delegate:permanent-delegate" - "token-groups-and-members:token-groups" - "transfer-fees:transfer-fees" - "transfer-hook:transfer-hook" -) - -# Function to wrap TypeScript code in markdown -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" - echo "Created: $output_file" -} - -echo "=== Processing extension snippets ===" -echo "" - -for mapping in "${EXTENSIONS[@]}"; do - source_name="${mapping%%:*}" - output_name="${mapping##*:}" - - src="$EXAMPLES/$source_name.ts" - if [ -f "$src" ]; then - wrap_typescript "$src" "$SNIPPETS_DIR/$output_name/action.mdx" - else - echo " WARNING: Not found - $src" - fi -done - -echo "" -echo "Done! Created snippets in: $SNIPPETS_DIR" -echo "" -echo "Files created:" -find "$SNIPPETS_DIR" -name "*.mdx" -type f | sort diff --git a/scripts/generate-llms-txt.js b/scripts/generate-llms-txt.js index a42bb6f..0afefa5 100644 --- a/scripts/generate-llms-txt.js +++ b/scripts/generate-llms-txt.js @@ -181,7 +181,7 @@ function splitLightTokenProgram(group) { for (const entry of group.pages) { if (typeof entry === 'string') { basics.push(formatPage(entry)); - } else if (entry.group === 'Cookbook' || entry.group === 'Examples' || entry.group === 'Extensions') { + } else if (entry.group === 'Cookbook' || entry.group === 'Examples') { basics.push(...collectFlatPages(entry.pages)); } else if (entry.group === 'For Stablecoin Payments') { paymentsWallets.push(...collectFlatPages(entry.pages)); diff --git a/skill.md b/skill.md index 541783a..89e1841 100644 --- a/skill.md +++ b/skill.md @@ -169,7 +169,6 @@ Use rent-free PDAs for: user state, app state, nullifiers for payments, DePIN no | Sign with Privy | Integrate light-token with Privy embedded wallets for rent-free token accounts and transfers. | [privy](https://zkcompression.com/light-token/wallets/privy) | [sign-with-privy](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-privy) | | Sign with Wallet Adapter | Integrate light-token with Solana Wallet Adapter for rent-free token accounts and transfers. | [wallet-adapter](https://zkcompression.com/light-token/wallets/wallet-adapter) | [sign-with-wallet-adapter](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/sign-with-wallet-adapter) | | Gasless transactions | Abstract SOL fees so users never hold SOL. Sponsor top-ups and transaction fees by setting your application as the fee payer. | [gasless-transactions](https://zkcompression.com/light-token/wallets/gasless-transactions) | [gasless-transactions](https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/gasless-transactions) | -| Smart wallets | Send Light Tokens from PDA-based smart wallets. Covers off-curve associated token account creation, instruction-level transfers, and sync and async execution with Squads. | [smart-wallets](https://zkcompression.com/light-token/wallets/smart-wallets) | | ## Examples @@ -258,21 +257,6 @@ CPI calls can be combined with existing and/or light macros. The API is a supers | `ThawCpi` | [freeze-thaw](https://zkcompression.com/light-token/cookbook/freeze-thaw) | [src](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/thaw/src/lib.rs) | | `CloseAccountCpi` | [close-token-account](https://zkcompression.com/light-token/cookbook/close-token-account) | [src](https://github.com/Lightprotocol/examples-light-token/blob/main/programs/anchor/basic-instructions/close/src/lib.rs) | -### Extensions - -| Extension | Docs guide | GitHub example | -|-----------|-----------|----------------| -| Close mint | [close-mint](https://zkcompression.com/light-token/extensions/close-mint) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/close-mint.ts) | -| Confidential transfer | [confidential-transfer](https://zkcompression.com/light-token/extensions/confidential-transfer) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/confidential-transfer.ts) | -| Default account state | [default-account-state](https://zkcompression.com/light-token/extensions/default-account-state) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/default-account-state.ts) | -| Interest-bearing tokens | [interest-bearing-tokens](https://zkcompression.com/light-token/extensions/interest-bearing-tokens) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/interest-bearing-tokens.ts) | -| Metadata and metadata pointer | [metadata-and-metadata-pointer](https://zkcompression.com/light-token/extensions/metadata-and-metadata-pointer) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/metadata-and-metadata-pointer.ts) | -| Pausable mint | [pausable-mint](https://zkcompression.com/light-token/extensions/pausable-mint) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/pausable-mint.ts) | -| Permanent delegate | [permanent-delegate](https://zkcompression.com/light-token/extensions/permanent-delegate) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/permanent-delegate.ts) | -| Token groups and members | [token-groups-and-members](https://zkcompression.com/light-token/extensions/token-groups-and-members) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts) | -| Transfer fees | [transfer-fees](https://zkcompression.com/light-token/extensions/transfer-fees) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-fees.ts) | -| Transfer hook | [transfer-hook](https://zkcompression.com/light-token/extensions/transfer-hook) | [example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-hook.ts) | - ## SDK references ### TypeScript packages diff --git a/snippets/ai-prompts/all-prompts.mdx b/snippets/ai-prompts/all-prompts.mdx index 51816f5..a221fc9 100644 --- a/snippets/ai-prompts/all-prompts.mdx +++ b/snippets/ai-prompts/all-prompts.mdx @@ -31,18 +31,6 @@ import WalletAdapter from "/snippets/ai-prompts/wallets/wallet-adapter.mdx"; import Privy from "/snippets/ai-prompts/wallets/privy.mdx"; import GaslessTransactions from "/snippets/ai-prompts/wallets/gasless-transactions.mdx"; -{/* extensions */} -import ExtCloseMint from "/snippets/ai-prompts/extensions/close-mint.mdx"; -import ExtConfidentialTransfer from "/snippets/ai-prompts/extensions/confidential-transfer.mdx"; -import ExtDefaultAccountState from "/snippets/ai-prompts/extensions/default-account-state.mdx"; -import ExtInterestBearing from "/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx"; -import ExtMetadataPointer from "/snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx"; -import ExtPausableMint from "/snippets/ai-prompts/extensions/pausable-mint.mdx"; -import ExtPermanentDelegate from "/snippets/ai-prompts/extensions/permanent-delegate.mdx"; -import ExtTokenGroups from "/snippets/ai-prompts/extensions/token-groups-and-members.mdx"; -import ExtTransferFees from "/snippets/ai-prompts/extensions/transfer-fees.mdx"; -import ExtTransferHook from "/snippets/ai-prompts/extensions/transfer-hook.mdx"; - {/* migration */} import V1ToV2Migration from "/snippets/ai-prompts/v1-to-v2-migration.mdx"; @@ -158,54 +146,3 @@ Copy the prompt below or view the [guide](/resources/migration-v1-to-v2).
-## Extensions - - -Copy the prompt below or view the [guide](/light-token/extensions/close-mint). - - - - -Copy the prompt below or view the [guide](/light-token/extensions/confidential-transfer). - - - - -Copy the prompt below or view the [guide](/light-token/extensions/default-account-state). - - - - -Copy the prompt below or view the [guide](/light-token/extensions/interest-bearing-tokens). - - - - -Copy the prompt below or view the [guide](/light-token/extensions/metadata-and-metadata-pointer). - - - - -Copy the prompt below or view the [guide](/light-token/extensions/pausable-mint). - - - - -Copy the prompt below or view the [guide](/light-token/extensions/permanent-delegate). - - - - -Copy the prompt below or view the [guide](/light-token/extensions/token-groups-and-members). - - - - -Copy the prompt below or view the [guide](/light-token/extensions/transfer-fees). - - - - -Copy the prompt below or view the [guide](/light-token/extensions/transfer-hook). - - \ No newline at end of file diff --git a/snippets/ai-prompts/extensions/close-mint.mdx b/snippets/ai-prompts/extensions/close-mint.mdx deleted file mode 100644 index 098eb24..0000000 --- a/snippets/ai-prompts/extensions/close-mint.mdx +++ /dev/null @@ -1,123 +0,0 @@ - -{`--- -description: Create a Token-2022 mint with MintCloseAuthority and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with MintCloseAuthority and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/close-mint -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Restriction: compression_only accounts required - -SPL equivalent: createInitializeMintCloseAuthorityInstruction() + createMint() -Light Token: createInitializeMintCloseAuthorityInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep \`@solana/spl-token|Connection|Keypair|MintCloseAuthority|TOKEN_2022\` across src/ -- Glob \`**/*.ts\` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with close authority -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with close authority, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Note: mint can only be closed when total supply is zero (all tokens burned) -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` -- Create T22 mint: getMintLen([ExtensionType.MintCloseAuthority]) → SystemProgram.createAccount → createInitializeMintCloseAuthorityInstruction(closeAuthority) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash \`tsc --noEmit\` -- Bash run existing test suite if present -- Confirm close authority address is set correctly -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work`} - - -```text ---- -description: Create a Token-2022 mint with MintCloseAuthority and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with MintCloseAuthority and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/close-mint -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Restriction: compression_only accounts required - -SPL equivalent: createInitializeMintCloseAuthorityInstruction() + createMint() -Light Token: createInitializeMintCloseAuthorityInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep `@solana/spl-token|Connection|Keypair|MintCloseAuthority|TOKEN_2022` across src/ -- Glob `**/*.ts` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with close authority -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with close authority, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Note: mint can only be closed when total supply is zero (all tokens burned) -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` -- Create T22 mint: getMintLen([ExtensionType.MintCloseAuthority]) → SystemProgram.createAccount → createInitializeMintCloseAuthorityInstruction(closeAuthority) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash `tsc --noEmit` -- Bash run existing test suite if present -- Confirm close authority address is set correctly -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work -``` diff --git a/snippets/ai-prompts/extensions/confidential-transfer.mdx b/snippets/ai-prompts/extensions/confidential-transfer.mdx deleted file mode 100644 index 5254423..0000000 --- a/snippets/ai-prompts/extensions/confidential-transfer.mdx +++ /dev/null @@ -1,123 +0,0 @@ - -{`--- -description: Create a Token-2022 mint with ConfidentialTransferMint and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with ConfidentialTransferMint and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/confidential-transfer -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Restriction: initialized but NOT enabled - -SPL equivalent: createInitializeConfidentialTransferMintInstruction() (or custom builder) -Light Token: createInitializeConfidentialTransferMintInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep \`@solana/spl-token|Connection|Keypair|ConfidentialTransfer|TOKEN_2022\` across src/ -- Glob \`**/*.ts\` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with confidential transfer -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with confidential transfer, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Ensure extension is initialized but NOT enabled — Light Token does not support active confidential transfers -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` -- Create T22 mint: getMintLen([ExtensionType.ConfidentialTransferMint]) → SystemProgram.createAccount → initialize ConfidentialTransferMint (custom instruction builder) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash \`tsc --noEmit\` -- Bash run existing test suite if present -- Confirm extension is initialized but not enabled -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work`} - - -```text ---- -description: Create a Token-2022 mint with ConfidentialTransferMint and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with ConfidentialTransferMint and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/confidential-transfer -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Restriction: initialized but NOT enabled - -SPL equivalent: createInitializeConfidentialTransferMintInstruction() (or custom builder) -Light Token: createInitializeConfidentialTransferMintInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep `@solana/spl-token|Connection|Keypair|ConfidentialTransfer|TOKEN_2022` across src/ -- Glob `**/*.ts` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with confidential transfer -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with confidential transfer, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Ensure extension is initialized but NOT enabled — Light Token does not support active confidential transfers -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` -- Create T22 mint: getMintLen([ExtensionType.ConfidentialTransferMint]) → SystemProgram.createAccount → initialize ConfidentialTransferMint (custom instruction builder) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash `tsc --noEmit` -- Bash run existing test suite if present -- Confirm extension is initialized but not enabled -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work -``` diff --git a/snippets/ai-prompts/extensions/default-account-state.mdx b/snippets/ai-prompts/extensions/default-account-state.mdx deleted file mode 100644 index 7667cf1..0000000 --- a/snippets/ai-prompts/extensions/default-account-state.mdx +++ /dev/null @@ -1,123 +0,0 @@ - -{`--- -description: Create a Token-2022 mint with DefaultAccountState and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with DefaultAccountState and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/default-account-state -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Restriction: compression_only accounts required - -SPL equivalent: createInitializeDefaultAccountStateInstruction() + createMint() -Light Token: createInitializeDefaultAccountStateInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep \`@solana/spl-token|Connection|Keypair|DefaultAccountState|TOKEN_2022\` across src/ -- Glob \`**/*.ts\` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with default account state -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with default account state, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Ensure a freeze authority is set (required when default state is Frozen) -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` -- Create T22 mint: getMintLen([ExtensionType.DefaultAccountState]) → SystemProgram.createAccount → createInitializeDefaultAccountStateInstruction(AccountState.Frozen) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash \`tsc --noEmit\` -- Bash run existing test suite if present -- Confirm freeze authority is set in initialization code -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work`} - - -```text ---- -description: Create a Token-2022 mint with DefaultAccountState and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with DefaultAccountState and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/default-account-state -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Restriction: compression_only accounts required - -SPL equivalent: createInitializeDefaultAccountStateInstruction() + createMint() -Light Token: createInitializeDefaultAccountStateInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep `@solana/spl-token|Connection|Keypair|DefaultAccountState|TOKEN_2022` across src/ -- Glob `**/*.ts` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with default account state -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with default account state, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Ensure a freeze authority is set (required when default state is Frozen) -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` -- Create T22 mint: getMintLen([ExtensionType.DefaultAccountState]) → SystemProgram.createAccount → createInitializeDefaultAccountStateInstruction(AccountState.Frozen) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash `tsc --noEmit` -- Bash run existing test suite if present -- Confirm freeze authority is set in initialization code -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work -``` diff --git a/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx b/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx deleted file mode 100644 index 3d7d5cc..0000000 --- a/snippets/ai-prompts/extensions/interest-bearing-tokens.mdx +++ /dev/null @@ -1,117 +0,0 @@ - -{`--- -description: Create a Token-2022 mint with InterestBearingConfig and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with InterestBearingConfig and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/interest-bearing-tokens -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token - -SPL equivalent: createInitializeInterestBearingMintInstruction() -Light Token: createInitializeInterestBearingMintInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep \`@solana/spl-token|Connection|Keypair|InterestBearing|TOKEN_2022\` across src/ -- Glob \`**/*.ts\` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with interest bearing -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with interest bearing, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` -- Create T22 mint: getMintLen([ExtensionType.InterestBearingConfig]) → SystemProgram.createAccount → createInitializeInterestBearingMintInstruction → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash \`tsc --noEmit\` -- Bash run existing test suite if present -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work`} - - -```text ---- -description: Create a Token-2022 mint with InterestBearingConfig and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with InterestBearingConfig and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/interest-bearing-tokens -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token - -SPL equivalent: createInitializeInterestBearingMintInstruction() -Light Token: createInitializeInterestBearingMintInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep `@solana/spl-token|Connection|Keypair|InterestBearing|TOKEN_2022` across src/ -- Glob `**/*.ts` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with interest bearing -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with interest bearing, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` -- Create T22 mint: getMintLen([ExtensionType.InterestBearingConfig]) → SystemProgram.createAccount → createInitializeInterestBearingMintInstruction → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash `tsc --noEmit` -- Bash run existing test suite if present -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work -``` diff --git a/snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx b/snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx deleted file mode 100644 index 3282b3d..0000000 --- a/snippets/ai-prompts/extensions/metadata-and-metadata-pointer.mdx +++ /dev/null @@ -1,117 +0,0 @@ - -{`--- -description: Create a Token-2022 mint with MetadataPointer and TokenMetadata and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with MetadataPointer and TokenMetadata and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/metadata-and-metadata-pointer -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token, @solana/spl-token-metadata - -SPL equivalent: createInitializeMetadataPointerInstruction() + createInitializeTokenMetadataInstruction() -Light Token: createInitializeMetadataPointerInstruction() + createInitializeTokenMetadataInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep \`@solana/spl-token|Connection|Keypair|MetadataPointer|TOKEN_2022\` across src/ -- Glob \`**/*.ts\` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with metadata extension -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with metadata, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token @solana/spl-token-metadata\` -- Create T22 mint: getMintLen([ExtensionType.MetadataPointer]) → SystemProgram.createAccount → createInitializeMetadataPointerInstruction → createInitializeMint2Instruction → createInitializeTokenMetadataInstruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash \`tsc --noEmit\` -- Bash run existing test suite if present -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work`} - - -```text ---- -description: Create a Token-2022 mint with MetadataPointer and TokenMetadata and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with MetadataPointer and TokenMetadata and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/metadata-and-metadata-pointer -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token, @solana/spl-token-metadata - -SPL equivalent: createInitializeMetadataPointerInstruction() + createInitializeTokenMetadataInstruction() -Light Token: createInitializeMetadataPointerInstruction() + createInitializeTokenMetadataInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep `@solana/spl-token|Connection|Keypair|MetadataPointer|TOKEN_2022` across src/ -- Glob `**/*.ts` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with metadata extension -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with metadata, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token @solana/spl-token-metadata` -- Create T22 mint: getMintLen([ExtensionType.MetadataPointer]) → SystemProgram.createAccount → createInitializeMetadataPointerInstruction → createInitializeMint2Instruction → createInitializeTokenMetadataInstruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash `tsc --noEmit` -- Bash run existing test suite if present -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work -``` diff --git a/snippets/ai-prompts/extensions/pausable-mint.mdx b/snippets/ai-prompts/extensions/pausable-mint.mdx deleted file mode 100644 index 0cc0acc..0000000 --- a/snippets/ai-prompts/extensions/pausable-mint.mdx +++ /dev/null @@ -1,123 +0,0 @@ - -{`--- -description: Create a Token-2022 mint with Pausable and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with Pausable and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/pausable-mint -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Restriction: compression_only accounts required - -SPL equivalent: createInitializePausableInstruction() + createMint() -Light Token: createInitializePausableInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep \`@solana/spl-token|Connection|Keypair|Pausable|TOKEN_2022\` across src/ -- Glob \`**/*.ts\` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with pausable -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with pausable, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Note: when paused, all minting, burning, and transfers are rejected until resumed -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` -- Create T22 mint: getMintLen([ExtensionType.PausableConfig]) → SystemProgram.createAccount → createInitializePausableConfigInstruction(pauseAuthority) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash \`tsc --noEmit\` -- Bash run existing test suite if present -- Confirm pause authority is set correctly -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work`} - - -```text ---- -description: Create a Token-2022 mint with Pausable and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with Pausable and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/pausable-mint -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Restriction: compression_only accounts required - -SPL equivalent: createInitializePausableInstruction() + createMint() -Light Token: createInitializePausableInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep `@solana/spl-token|Connection|Keypair|Pausable|TOKEN_2022` across src/ -- Glob `**/*.ts` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with pausable -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with pausable, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Note: when paused, all minting, burning, and transfers are rejected until resumed -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` -- Create T22 mint: getMintLen([ExtensionType.PausableConfig]) → SystemProgram.createAccount → createInitializePausableConfigInstruction(pauseAuthority) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash `tsc --noEmit` -- Bash run existing test suite if present -- Confirm pause authority is set correctly -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work -``` diff --git a/snippets/ai-prompts/extensions/permanent-delegate.mdx b/snippets/ai-prompts/extensions/permanent-delegate.mdx deleted file mode 100644 index 7758b41..0000000 --- a/snippets/ai-prompts/extensions/permanent-delegate.mdx +++ /dev/null @@ -1,123 +0,0 @@ - -{`--- -description: Create a Token-2022 mint with PermanentDelegate and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with PermanentDelegate and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/permanent-delegate -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Restriction: compression_only accounts required - -SPL equivalent: createInitializePermanentDelegateInstruction() + createMint() -Light Token: createInitializePermanentDelegateInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep \`@solana/spl-token|Connection|Keypair|PermanentDelegate|TOKEN_2022\` across src/ -- Glob \`**/*.ts\` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with permanent delegate -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with permanent delegate, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Ensure the delegate address is correct — this authority is irrevocable once set -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` -- Create T22 mint: getMintLen([ExtensionType.PermanentDelegate]) → SystemProgram.createAccount → createInitializePermanentDelegateInstruction(delegate) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash \`tsc --noEmit\` -- Bash run existing test suite if present -- Confirm delegate address is intentional (irrevocable) -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work`} - - -```text ---- -description: Create a Token-2022 mint with PermanentDelegate and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with PermanentDelegate and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/permanent-delegate -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Restriction: compression_only accounts required - -SPL equivalent: createInitializePermanentDelegateInstruction() + createMint() -Light Token: createInitializePermanentDelegateInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep `@solana/spl-token|Connection|Keypair|PermanentDelegate|TOKEN_2022` across src/ -- Glob `**/*.ts` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with permanent delegate -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with permanent delegate, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Ensure the delegate address is correct — this authority is irrevocable once set -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` -- Create T22 mint: getMintLen([ExtensionType.PermanentDelegate]) → SystemProgram.createAccount → createInitializePermanentDelegateInstruction(delegate) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash `tsc --noEmit` -- Bash run existing test suite if present -- Confirm delegate address is intentional (irrevocable) -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work -``` diff --git a/snippets/ai-prompts/extensions/token-groups-and-members.mdx b/snippets/ai-prompts/extensions/token-groups-and-members.mdx deleted file mode 100644 index 2f297ab..0000000 --- a/snippets/ai-prompts/extensions/token-groups-and-members.mdx +++ /dev/null @@ -1,123 +0,0 @@ - -{`--- -description: Create Token-2022 group and member mints and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create Token-2022 group and member mints and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/token-groups-and-members -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token - -SPL equivalent: createInitializeGroupPointerInstruction() + createInitializeGroupInstruction() -Light Token: createInitializeGroupPointerInstruction() + createInitializeGroupInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep \`@solana/spl-token|Connection|Keypair|GroupPointer|TOKEN_2022\` across src/ -- Glob \`**/*.ts\` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 group and member mints -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 group/member mints, register existing T22 mints, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Plan covers both group mint creation (GroupPointer + TokenGroup) and member mint creation (GroupMemberPointer + TokenGroupMember) -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` -- Create group mint: getMintLen([ExtensionType.GroupPointer, ExtensionType.TokenGroup]) → SystemProgram.createAccount → createInitializeGroupPointerInstruction → createInitializeMint2Instruction → createInitializeGroupInstruction -- Create member mint: getMintLen([ExtensionType.GroupMemberPointer, ExtensionType.TokenGroupMember]) → SystemProgram.createAccount → createInitializeGroupMemberPointerInstruction → createInitializeMint2Instruction → createInitializeMemberInstruction -- Register both mints: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash \`tsc --noEmit\` -- Bash run existing test suite if present -- Confirm both group and member mints are created and registered -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work`} - - -```text ---- -description: Create Token-2022 group and member mints and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create Token-2022 group and member mints and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/token-groups-and-members -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token - -SPL equivalent: createInitializeGroupPointerInstruction() + createInitializeGroupInstruction() -Light Token: createInitializeGroupPointerInstruction() + createInitializeGroupInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep `@solana/spl-token|Connection|Keypair|GroupPointer|TOKEN_2022` across src/ -- Glob `**/*.ts` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 group and member mints -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 group/member mints, register existing T22 mints, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Plan covers both group mint creation (GroupPointer + TokenGroup) and member mint creation (GroupMemberPointer + TokenGroupMember) -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` -- Create group mint: getMintLen([ExtensionType.GroupPointer, ExtensionType.TokenGroup]) → SystemProgram.createAccount → createInitializeGroupPointerInstruction → createInitializeMint2Instruction → createInitializeGroupInstruction -- Create member mint: getMintLen([ExtensionType.GroupMemberPointer, ExtensionType.TokenGroupMember]) → SystemProgram.createAccount → createInitializeGroupMemberPointerInstruction → createInitializeMint2Instruction → createInitializeMemberInstruction -- Register both mints: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash `tsc --noEmit` -- Bash run existing test suite if present -- Confirm both group and member mints are created and registered -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work -``` diff --git a/snippets/ai-prompts/extensions/transfer-fees.mdx b/snippets/ai-prompts/extensions/transfer-fees.mdx deleted file mode 100644 index 409fe1f..0000000 --- a/snippets/ai-prompts/extensions/transfer-fees.mdx +++ /dev/null @@ -1,123 +0,0 @@ - -{`--- -description: Create a Token-2022 mint with TransferFeeConfig and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with TransferFeeConfig and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/transfer-fees -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Constraint: fees MUST be zero (0 basis points, 0 maximum fee) - -SPL equivalent: createInitializeTransferFeeConfigInstruction() + createMint() -Light Token: createInitializeTransferFeeConfigInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep \`@solana/spl-token|Connection|Keypair|TransferFee|TOKEN_2022\` across src/ -- Glob \`**/*.ts\` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with transfer fee extension -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with transfer fees, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Ensure fees are zero (0 basis points, BigInt(0) max fee) — non-zero fees cause Light Token registration to fail -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` -- Create T22 mint: getMintLen([ExtensionType.TransferFeeConfig]) → SystemProgram.createAccount → createInitializeTransferFeeConfigInstruction (zero fees) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash \`tsc --noEmit\` -- Bash run existing test suite if present -- Confirm fees are zero in initialization code -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work`} - - -```text ---- -description: Create a Token-2022 mint with TransferFeeConfig and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with TransferFeeConfig and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/transfer-fees -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Constraint: fees MUST be zero (0 basis points, 0 maximum fee) - -SPL equivalent: createInitializeTransferFeeConfigInstruction() + createMint() -Light Token: createInitializeTransferFeeConfigInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep `@solana/spl-token|Connection|Keypair|TransferFee|TOKEN_2022` across src/ -- Glob `**/*.ts` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with transfer fee extension -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with transfer fees, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Ensure fees are zero (0 basis points, BigInt(0) max fee) — non-zero fees cause Light Token registration to fail -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` -- Create T22 mint: getMintLen([ExtensionType.TransferFeeConfig]) → SystemProgram.createAccount → createInitializeTransferFeeConfigInstruction (zero fees) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash `tsc --noEmit` -- Bash run existing test suite if present -- Confirm fees are zero in initialization code -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work -``` diff --git a/snippets/ai-prompts/extensions/transfer-hook.mdx b/snippets/ai-prompts/extensions/transfer-hook.mdx deleted file mode 100644 index 1d09408..0000000 --- a/snippets/ai-prompts/extensions/transfer-hook.mdx +++ /dev/null @@ -1,123 +0,0 @@ - -{`--- -description: Create a Token-2022 mint with TransferHook and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with TransferHook and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/transfer-hook -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Constraint: program_id MUST be nil (PublicKey.default) - -SPL equivalent: createInitializeTransferHookInstruction() -Light Token: createInitializeTransferHookInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep \`@solana/spl-token|Connection|Keypair|TransferHook|TOKEN_2022\` across src/ -- Glob \`**/*.ts\` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with transfer hook -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with transfer hook, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Ensure program_id is PublicKey.default (nil) — non-nil program_id causes Light Token registration to fail -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token\` -- Create T22 mint: getMintLen([ExtensionType.TransferHook]) → SystemProgram.createAccount → createInitializeTransferHookInstruction (PublicKey.default) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash \`tsc --noEmit\` -- Bash run existing test suite if present -- Confirm program_id is PublicKey.default in initialization code -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work`} - - -```text ---- -description: Create a Token-2022 mint with TransferHook and register with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Create a Token-2022 mint with TransferHook and register with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/extensions/transfer-hook -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @solana/spl-token -- Constraint: program_id MUST be nil (PublicKey.default) - -SPL equivalent: createInitializeTransferHookInstruction() -Light Token: createInitializeTransferHookInstruction() + LightTokenProgram.createSplInterface() - -### 1. Index project -- Grep `@solana/spl-token|Connection|Keypair|TransferHook|TOKEN_2022` across src/ -- Glob `**/*.ts` for project structure -- Identify: RPC setup, existing mint logic, entry point for T22 mint with transfer hook -- Task subagent (Grep/Read/WebFetch) if project has multiple packages to scan in parallel - -### 2. Read references -- WebFetch the guide above — follow the Instruction tab for the full flow -- WebFetch skill.md — check for a dedicated skill and resources matching this task -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (new T22 mint with transfer hook, register existing T22 mint, migrate existing SPL code) -- AskUserQuestion: does the project already use Token-2022? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft an implementation plan: which files to modify, what code to add, dependency changes -- Verify existing connection/signer setup is compatible with the cookbook prerequisites -- Ensure program_id is PublicKey.default (nil) — non-nil program_id causes Light Token registration to fail -- If anything is unclear or ambiguous, loop back to step 3 (AskUserQuestion) -- Present the plan to the user for approval before proceeding - -### 5. Implement -- Add deps if missing: Bash `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @solana/spl-token` -- Create T22 mint: getMintLen([ExtensionType.TransferHook]) → SystemProgram.createAccount → createInitializeTransferHookInstruction (PublicKey.default) → createInitializeMint2Instruction -- Register with Light Token: LightTokenProgram.createSplInterface({ mint, tokenProgramId: TOKEN_2022_PROGRAM_ID }) -- Transfer: createTransferInterfaceInstructions() from @lightprotocol/compressed-token/unified -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash `tsc --noEmit` -- Bash run existing test suite if present -- Confirm program_id is PublicKey.default in initialization code -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work -``` diff --git a/snippets/ai-prompts/toolkits/payments.mdx b/snippets/ai-prompts/toolkits/payments.mdx index 3eeeebe..dacae5a 100644 --- a/snippets/ai-prompts/toolkits/payments.mdx +++ b/snippets/ai-prompts/toolkits/payments.mdx @@ -18,7 +18,7 @@ SPL → Light Token API mapping: | Operation | SPL | Light Token | | Receive | getOrCreateAssociatedTokenAccount() | createLoadAtaInstructions() / loadAta() | | Transfer | createTransferInstruction() | createTransferInterfaceInstructions() | -| Delegated Transfer | transfer() (delegate signs) | transferDelegatedInterface() | +| Delegated Transfer | transfer() (delegate signs) | transferInterface({ owner }) | | Get Balance | getAccount() | getAtaInterface() | | Tx History | getSignaturesForAddress() | getSignaturesForOwnerInterface() | | Wrap SPL | N/A | createWrapInstruction() / wrap() | @@ -89,7 +89,7 @@ SPL → Light Token API mapping: | Operation | SPL | Light Token | | Receive | getOrCreateAssociatedTokenAccount() | createLoadAtaInstructions() / loadAta() | | Transfer | createTransferInstruction() | createTransferInterfaceInstructions() | -| Delegated Transfer | transfer() (delegate signs) | transferDelegatedInterface() | +| Delegated Transfer | transfer() (delegate signs) | transferInterface({ owner }) | | Get Balance | getAccount() | getAtaInterface() | | Tx History | getSignaturesForAddress() | getSignaturesForOwnerInterface() | | Wrap SPL | N/A | createWrapInstruction() / wrap() | diff --git a/snippets/ai-prompts/wallets/smart-wallets.mdx b/snippets/ai-prompts/wallets/smart-wallets.mdx deleted file mode 100644 index a61a780..0000000 --- a/snippets/ai-prompts/wallets/smart-wallets.mdx +++ /dev/null @@ -1,159 +0,0 @@ - -{`--- -description: Smart wallet integration with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Smart wallet integration with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/wallets/smart-wallets -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets -- Full example: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/smart-wallet -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @sqds/smart-account - -How smart wallets differ from standard wallets: -- The wallet is a PDA (off-curve) and not a valid keypair -- \`transferInterface()\` and \`createTransferInterfaceInstructions()\` reject off-curve addresses -- Use \`createLightTokenTransferInstruction()\` instead. It accepts any PublicKey -- Associated token account creation needs \`allowOwnerOffCurve=true\`: \`createAtaInterface(rpc, payer, mint, walletPda, true)\` -- The smart wallet program signs via CPI, not with a keypair - -Key APIs: -| Function | Purpose | Off-curve note | -| \`createLightTokenTransferInstruction(src, dest, owner, amount, feePayer?)\` | Build transfer instruction | Accepts any PublicKey as owner | -| \`createAtaInterface(rpc, payer, mint, owner, allowOwnerOffCurve?)\` | Create associated token account | 5th arg must be \`true\` for PDAs | -| \`smartAccount.instructions.executeTransactionSync()\` | Sync execution | Single tx, all signers + timeLock=0 | -| \`smartAccount.rpc.createTransaction/createProposal/approveProposal/executeTransaction\` | Async governance flow | Multi-step, any threshold | - -### 1. Index project -- Grep \`smartAccount|createLightTokenTransferInstruction|@sqds|@lightprotocol|allowOwnerOffCurve|walletPda\` across src/ -- Glob \`**/*.ts\` and \`**/*.tsx\` for project structure -- Identify: existing smart wallet setup, token operations, execution mode (sync vs async) -- Check package.json for @lightprotocol/*, @sqds/smart-account dependencies -- Task subagent (Grep/Read/WebFetch) if project has multiple packages - -### 2. Read references -- WebFetch the guide above. Review code examples for off-curve ATA and transfer patterns -- WebFetch skill.md. Check for dedicated skill and resources -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (add Light Token support to existing smart wallet, new integration from scratch, migrate from SPL to Light Token) -- AskUserQuestion: which smart wallet program? (Squads, custom, other) -- AskUserQuestion: sync execution, async governance, or both? -- AskUserQuestion: does the wallet already exist on-chain or needs creation? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft implementation plan -- Key patterns: - - \`createAtaInterface(rpc, payer, mint, walletPda, true)\` for off-curve ATA - - \`createLightTokenTransferInstruction(src, dest, walletPda, amount, walletPda)\` for transfers - - Wrap in smart wallet execution (sync or async depending on config) -- If anything is unclear, loop back to step 3 -- Present the plan to the user for approval - -### 5. Implement -- Add deps if missing: \`npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @sqds/smart-account\` -- Set up RPC: \`createRpc(RPC_ENDPOINT)\` with a ZK Compression endpoint (Helius, Triton) -- Import \`createLightTokenTransferInstruction\`, \`createAtaInterface\`, \`getAssociatedTokenAddressInterface\` from \`@lightprotocol/compressed-token\` -- Create off-curve associated token account for the wallet PDA -- Build transfer instruction with wallet PDA as owner -- Wrap in smart wallet execution (sync: \`executeTransactionSync\`, async: createTransaction → createProposal → approveProposal → executeTransaction) -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash \`tsc --noEmit\` -- Bash run existing test suite if present -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work`} - - -```text ---- -description: Smart wallet integration with Light Token -allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, AskUserQuestion, Task, TaskCreate, TaskGet, TaskList, TaskUpdate, TaskOutput, mcp__deepwiki, mcp__zkcompression ---- - -## Smart wallet integration with Light Token - -Context: -- Guide: https://zkcompression.com/light-token/wallets/smart-wallets -- Skills and resources index: https://zkcompression.com/skill.md -- SPL to Light reference: https://zkcompression.com/api-reference/solana-to-light-comparison -- Dedicated skill: https://github.com/Lightprotocol/skills/tree/main/skills/payments-and-wallets -- Full example: https://github.com/Lightprotocol/examples-light-token/tree/main/toolkits/smart-wallet -- Packages: @lightprotocol/compressed-token, @lightprotocol/stateless.js, @sqds/smart-account - -How smart wallets differ from standard wallets: -- The wallet is a PDA (off-curve) and not a valid keypair -- `transferInterface()` and `createTransferInterfaceInstructions()` reject off-curve addresses -- Use `createLightTokenTransferInstruction()` instead. It accepts any PublicKey -- ATA creation needs `allowOwnerOffCurve=true`: `createAtaInterface(rpc, payer, mint, walletPda, true)` -- The smart wallet program signs via CPI, not with a keypair - -Key APIs: -| Function | Purpose | Off-curve note | -| `createLightTokenTransferInstruction(src, dest, owner, amount, feePayer?)` | Build transfer instruction | Accepts any PublicKey as owner | -| `createAtaInterface(rpc, payer, mint, owner, allowOwnerOffCurve?)` | Create associated token account | 5th arg must be `true` for PDAs | -| `smartAccount.instructions.executeTransactionSync()` | Sync execution | Single tx, all signers + timeLock=0 | -| `smartAccount.rpc.createTransaction/createProposal/approveProposal/executeTransaction` | Async governance flow | Multi-step, any threshold | - -### 1. Index project -- Grep `smartAccount|createLightTokenTransferInstruction|@sqds|@lightprotocol|allowOwnerOffCurve|walletPda` across src/ -- Glob `**/*.ts` and `**/*.tsx` for project structure -- Identify: existing smart wallet setup, token operations, execution mode (sync vs async) -- Check package.json for @lightprotocol/*, @sqds/smart-account dependencies -- Task subagent (Grep/Read/WebFetch) if project has multiple packages - -### 2. Read references -- WebFetch the guide above. Review code examples for off-curve ATA and transfer patterns -- WebFetch skill.md. Check for dedicated skill and resources -- TaskCreate one todo per phase below to track progress - -### 3. Clarify intention -- AskUserQuestion: what is the goal? (add Light Token support to existing smart wallet, new integration from scratch, migrate from SPL to Light Token) -- AskUserQuestion: which smart wallet program? (Squads, custom, other) -- AskUserQuestion: sync execution, async governance, or both? -- AskUserQuestion: does the wallet already exist on-chain or needs creation? -- Summarize findings and wait for user confirmation before implementing - -### 4. Create plan -- Based on steps 1–3, draft implementation plan -- Key patterns: - - `createAtaInterface(rpc, payer, mint, walletPda, true)` for off-curve ATA - - `createLightTokenTransferInstruction(src, dest, walletPda, amount, walletPda)` for transfers - - Wrap in smart wallet execution (sync or async depending on config) -- If anything is unclear, loop back to step 3 -- Present the plan to the user for approval - -### 5. Implement -- Add deps if missing: `npm install @lightprotocol/compressed-token @lightprotocol/stateless.js @sqds/smart-account` -- Set up RPC: `createRpc(RPC_ENDPOINT)` with a ZK Compression endpoint (Helius, Triton) -- Import `createLightTokenTransferInstruction`, `createAtaInterface`, `getAssociatedTokenAddressInterface` from `@lightprotocol/compressed-token` -- Create off-curve associated token account for the wallet PDA -- Build transfer instruction with wallet PDA as owner -- Wrap in smart wallet execution (sync: `executeTransactionSync`, async: createTransaction → createProposal → approveProposal → executeTransaction) -- Write/Edit to create or modify files -- TaskUpdate to mark each step done - -### 6. Verify -- Bash `tsc --noEmit` -- Bash run existing test suite if present -- TaskUpdate to mark complete - -### Tools -- mcp__zkcompression__SearchLightProtocol("") for API details -- mcp__deepwiki__ask_question("Lightprotocol/light-protocol", "") for architecture -- Task subagent with Grep/Read/WebFetch for parallel lookups -- TaskList to check remaining work -``` diff --git a/snippets/code-snippets/light-token/delegate-transfer/action.mdx b/snippets/code-snippets/light-token/delegate-transfer/action.mdx index acb1760..a6ef57a 100644 --- a/snippets/code-snippets/light-token/delegate-transfer/action.mdx +++ b/snippets/code-snippets/light-token/delegate-transfer/action.mdx @@ -9,7 +9,7 @@ import { } from "@lightprotocol/compressed-token"; import { approveInterface, - transferDelegatedInterface, + transferInterface, } from "@lightprotocol/compressed-token/unified"; import { homedir } from "os"; import { readFileSync } from "fs"; @@ -49,15 +49,17 @@ const payer = Keypair.fromSecretKey( console.log("Approved delegate:", delegate.publicKey.toBase58()); // Delegate transfers tokens on behalf of the owner - const tx = await transferDelegatedInterface( + const tx = await transferInterface( rpc, payer, senderAta, mint, recipient.publicKey, delegate, - payer.publicKey, - 200_000 + 200_000, + undefined, + undefined, + { owner: payer.publicKey } ); console.log("Delegated transfer:", tx); diff --git a/snippets/code-snippets/light-token/extensions/close-mint/action.mdx b/snippets/code-snippets/light-token/extensions/close-mint/action.mdx deleted file mode 100644 index 194da71..0000000 --- a/snippets/code-snippets/light-token/extensions/close-mint/action.mdx +++ /dev/null @@ -1,91 +0,0 @@ -```typescript -import "dotenv/config"; -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - ExtensionType, - getMintLen, - createInitializeMint2Instruction, - createInitializeMintCloseAuthorityInstruction, -} from "@solana/spl-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 () { - const mintKeypair = Keypair.generate(); - const decimals = 9; - - // 1. Calculate space including the MintCloseAuthority extension - const mintLen = getMintLen([ExtensionType.MintCloseAuthority]); - const rentExemptBalance = await rpc.getMinimumBalanceForRentExemption( - mintLen - ); - - // 2. Create the mint account - const createMintAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, - }); - - // 3. Initialize the MintCloseAuthority extension - const initMintCloseAuthorityIx = - createInitializeMintCloseAuthorityInstruction( - mintKeypair.publicKey, - payer.publicKey, // close authority - TOKEN_2022_PROGRAM_ID - ); - - // 4. Initialize the mint - const initializeMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID - ); - - // 5. Register the SPL interface PDA with Light Token - const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); - - const tx = new Transaction().add( - createMintAccountIx, - initMintCloseAuthorityIx, - initializeMintIx, - createSplInterfaceIx - ); - - const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, - ]); - - console.log("Mint:", mintKeypair.publicKey.toBase58()); - console.log("Tx:", signature); -})(); -``` diff --git a/snippets/code-snippets/light-token/extensions/confidential-transfer/action.mdx b/snippets/code-snippets/light-token/extensions/confidential-transfer/action.mdx deleted file mode 100644 index a0e1201..0000000 --- a/snippets/code-snippets/light-token/extensions/confidential-transfer/action.mdx +++ /dev/null @@ -1,141 +0,0 @@ -```typescript -import "dotenv/config"; -import { - Keypair, - PublicKey, - SystemProgram, - Transaction, - TransactionInstruction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - ExtensionType, - TOKEN_2022_PROGRAM_ID, - createInitializeMint2Instruction, - getMintLen, -} from "@solana/spl-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")) - ) -); - -/** - * Build the InitializeMint instruction for ConfidentialTransferMint. - * - * The @solana/spl-token SDK defines ExtensionType.ConfidentialTransferMint - * but does not yet export a helper for this instruction, so we construct - * it manually using the Token-2022 instruction layout. - */ -function createInitializeConfidentialTransferMintIx( - mint: PublicKey, - authority: PublicKey | null, - autoApproveNewAccounts: boolean, - auditorElGamalPubkey: Uint8Array | null, -): TransactionInstruction { - // TokenInstruction::ConfidentialTransferExtension = 27 - // ConfidentialTransferInstruction::InitializeMint = 0 - const data = Buffer.alloc(2 + 1 + 32 + 1 + 1 + 32); - let offset = 0; - data.writeUInt8(27, offset); offset += 1; // TokenInstruction - data.writeUInt8(0, offset); offset += 1; // InitializeMint sub-instruction - - // authority (COption): 1 byte tag + 32 bytes - if (authority) { - data.writeUInt8(1, offset); offset += 1; - authority.toBuffer().copy(data, offset); offset += 32; - } else { - data.writeUInt8(0, offset); offset += 1; - offset += 32; - } - - // auto_approve_new_accounts: bool (1 byte) - data.writeUInt8(autoApproveNewAccounts ? 1 : 0, offset); offset += 1; - - // auditor_elgamal_pubkey (COption): 1 byte tag + 32 bytes - if (auditorElGamalPubkey) { - data.writeUInt8(1, offset); offset += 1; - Buffer.from(auditorElGamalPubkey).copy(data, offset); - } else { - data.writeUInt8(0, offset); offset += 1; - } - - return new TransactionInstruction({ - keys: [{ pubkey: mint, isSigner: false, isWritable: true }], - programId: TOKEN_2022_PROGRAM_ID, - data, - }); -} - -(async function () { - const mintKeypair = Keypair.generate(); - const decimals = 9; - - // 1. Calculate space including ConfidentialTransferMint extension - const mintLen = getMintLen([ExtensionType.ConfidentialTransferMint]); - const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - - // 2. Create account - const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, - }); - - // 3. Initialize ConfidentialTransferMint extension (must come before mint init) - // auto_approve_new_accounts: false — extension is initialized but not enabled - // auditor_elgamal_pubkey: null — no auditor configured - const initConfidentialTransferIx = - createInitializeConfidentialTransferMintIx( - mintKeypair.publicKey, - payer.publicKey, // authority - false, // auto_approve_new_accounts (not enabled) - null, // auditor_elgamal_pubkey - ); - - // 4. Initialize mint - const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID, - ); - - // 5. Register interface PDA with Light Token - const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); - - const tx = new Transaction().add( - createAccountIx, - initConfidentialTransferIx, - initMintIx, - createSplInterfaceIx, - ); - - const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, - ]); - - console.log("Mint:", mintKeypair.publicKey.toBase58()); - console.log("Tx:", signature); -})(); -``` diff --git a/snippets/code-snippets/light-token/extensions/default-account-state/action.mdx b/snippets/code-snippets/light-token/extensions/default-account-state/action.mdx deleted file mode 100644 index 5092884..0000000 --- a/snippets/code-snippets/light-token/extensions/default-account-state/action.mdx +++ /dev/null @@ -1,92 +0,0 @@ -```typescript -import "dotenv/config"; -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - ExtensionType, - getMintLen, - createInitializeMint2Instruction, - createInitializeDefaultAccountStateInstruction, - AccountState, -} from "@solana/spl-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 () { - const mintKeypair = Keypair.generate(); - const decimals = 9; - - // 1. Calculate space including the DefaultAccountState extension - const mintLen = getMintLen([ExtensionType.DefaultAccountState]); - const rentExemptBalance = await rpc.getMinimumBalanceForRentExemption( - mintLen - ); - - // 2. Create the mint account - const createMintAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, - }); - - // 3. Initialize the DefaultAccountState extension (frozen by default) - const initDefaultAccountStateIx = - createInitializeDefaultAccountStateInstruction( - mintKeypair.publicKey, - AccountState.Frozen, - TOKEN_2022_PROGRAM_ID - ); - - // 4. Initialize the mint - const initializeMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - payer.publicKey, // freeze authority (required for frozen default state) - TOKEN_2022_PROGRAM_ID - ); - - // 5. Register the SPL interface PDA with Light Token - const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); - - const tx = new Transaction().add( - createMintAccountIx, - initDefaultAccountStateIx, - initializeMintIx, - createSplInterfaceIx - ); - - const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, - ]); - - console.log("Mint:", mintKeypair.publicKey.toBase58()); - console.log("Tx:", signature); -})(); -``` diff --git a/snippets/code-snippets/light-token/extensions/interest-bearing/action.mdx b/snippets/code-snippets/light-token/extensions/interest-bearing/action.mdx deleted file mode 100644 index 1a6043e..0000000 --- a/snippets/code-snippets/light-token/extensions/interest-bearing/action.mdx +++ /dev/null @@ -1,93 +0,0 @@ -```typescript -import "dotenv/config"; -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - getMintLen, - createInitializeMint2Instruction, - ExtensionType, - createInitializeInterestBearingMintInstruction, -} from "@solana/spl-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 () { - const mintKeypair = Keypair.generate(); - const decimals = 9; - const rate = 500; // 5% interest rate in basis points - - // Calculate space for mint + InterestBearingConfig extension - const mintLen = getMintLen([ExtensionType.InterestBearingConfig]); - const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - - // Instruction 1: Create account - const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, - }); - - // Instruction 2: Initialize InterestBearingConfig - const initInterestBearingIx = - createInitializeInterestBearingMintInstruction( - mintKeypair.publicKey, - payer.publicKey, // rate authority - rate, - TOKEN_2022_PROGRAM_ID - ); - - // Instruction 3: Initialize mint - const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID - ); - - // Instruction 4: Create SPL interface PDA - // Holds Token-2022 tokens when wrapped to light-token - const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); - - const tx = new Transaction().add( - createAccountIx, - initInterestBearingIx, - initMintIx, - createSplInterfaceIx - ); - - const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, - ]); - - console.log("Mint:", mintKeypair.publicKey.toBase58()); - console.log("Tx:", signature); -})(); -``` diff --git a/snippets/code-snippets/light-token/extensions/metadata-pointer/action.mdx b/snippets/code-snippets/light-token/extensions/metadata-pointer/action.mdx deleted file mode 100644 index 6694b00..0000000 --- a/snippets/code-snippets/light-token/extensions/metadata-pointer/action.mdx +++ /dev/null @@ -1,120 +0,0 @@ -```typescript -import "dotenv/config"; -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - getMintLen, - createInitializeMint2Instruction, - ExtensionType, - createInitializeMetadataPointerInstruction, -} from "@solana/spl-token"; -import { - createInitializeInstruction as createInitializeTokenMetadataInstruction, - pack, - TokenMetadata, -} from "@solana/spl-token-metadata"; -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 () { - const mintKeypair = Keypair.generate(); - const decimals = 9; - - const metadata: TokenMetadata = { - mint: mintKeypair.publicKey, - name: "Example Token", - symbol: "EXT", - uri: "https://example.com/metadata.json", - additionalMetadata: [], - }; - - // Calculate space for mint + MetadataPointer extension - const mintLen = getMintLen([ExtensionType.MetadataPointer]); - const metadataLen = pack(metadata).length; - const totalLen = mintLen + metadataLen; - const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(totalLen); - - // Instruction 1: Create account - const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, - }); - - // Instruction 2: Initialize MetadataPointer (points to the mint itself) - const initMetadataPointerIx = - createInitializeMetadataPointerInstruction( - mintKeypair.publicKey, - payer.publicKey, - mintKeypair.publicKey, // metadata address = mint itself - TOKEN_2022_PROGRAM_ID - ); - - // Instruction 3: Initialize mint - const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID - ); - - // Instruction 4: Initialize TokenMetadata on the mint - const initTokenMetadataIx = createInitializeTokenMetadataInstruction({ - programId: TOKEN_2022_PROGRAM_ID, - mint: mintKeypair.publicKey, - metadata: mintKeypair.publicKey, - mintAuthority: payer.publicKey, - name: metadata.name, - symbol: metadata.symbol, - uri: metadata.uri, - updateAuthority: payer.publicKey, - }); - - // Instruction 5: Create SPL interface PDA - // Holds Token-2022 tokens when wrapped to light-token - const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); - - const tx = new Transaction().add( - createAccountIx, - initMetadataPointerIx, - initMintIx, - initTokenMetadataIx, - createSplInterfaceIx - ); - - const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, - ]); - - console.log("Mint:", mintKeypair.publicKey.toBase58()); - console.log("Tx:", signature); -})(); -``` diff --git a/snippets/code-snippets/light-token/extensions/pausable/action.mdx b/snippets/code-snippets/light-token/extensions/pausable/action.mdx deleted file mode 100644 index 4208424..0000000 --- a/snippets/code-snippets/light-token/extensions/pausable/action.mdx +++ /dev/null @@ -1,89 +0,0 @@ -```typescript -import "dotenv/config"; -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - ExtensionType, - TOKEN_2022_PROGRAM_ID, - createInitializeMint2Instruction, - createInitializePausableConfigInstruction, - getMintLen, -} from "@solana/spl-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 () { - const mintKeypair = Keypair.generate(); - const decimals = 9; - - // 1. Calculate space including the Pausable extension - const mintLen = getMintLen([ExtensionType.PausableConfig]); - const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - - // 2. Create account - const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, - }); - - // 3. Initialize Pausable extension (must come before mint init) - const initPausableIx = createInitializePausableConfigInstruction( - mintKeypair.publicKey, - payer.publicKey, // pause authority - TOKEN_2022_PROGRAM_ID, - ); - - // 4. Initialize mint - const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID, - ); - - // 5. Register interface PDA with Light Token - const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); - - const tx = new Transaction().add( - createAccountIx, - initPausableIx, - initMintIx, - createSplInterfaceIx, - ); - - const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, - ]); - - console.log("Mint:", mintKeypair.publicKey.toBase58()); - console.log("Tx:", signature); -})(); -``` diff --git a/snippets/code-snippets/light-token/extensions/permanent-delegate/action.mdx b/snippets/code-snippets/light-token/extensions/permanent-delegate/action.mdx deleted file mode 100644 index 9d8376b..0000000 --- a/snippets/code-snippets/light-token/extensions/permanent-delegate/action.mdx +++ /dev/null @@ -1,91 +0,0 @@ -```typescript -import "dotenv/config"; -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - ExtensionType, - getMintLen, - createInitializeMint2Instruction, - createInitializePermanentDelegateInstruction, -} from "@solana/spl-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 () { - const mintKeypair = Keypair.generate(); - const decimals = 9; - - // 1. Calculate space including the PermanentDelegate extension - const mintLen = getMintLen([ExtensionType.PermanentDelegate]); - const rentExemptBalance = await rpc.getMinimumBalanceForRentExemption( - mintLen - ); - - // 2. Create the mint account - const createMintAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, - }); - - // 3. Initialize the PermanentDelegate extension - const initPermanentDelegateIx = - createInitializePermanentDelegateInstruction( - mintKeypair.publicKey, - payer.publicKey, // permanent delegate authority - TOKEN_2022_PROGRAM_ID - ); - - // 4. Initialize the mint - const initializeMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID - ); - - // 5. Register the SPL interface PDA with Light Token - const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); - - const tx = new Transaction().add( - createMintAccountIx, - initPermanentDelegateIx, - initializeMintIx, - createSplInterfaceIx - ); - - const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, - ]); - - console.log("Mint:", mintKeypair.publicKey.toBase58()); - console.log("Tx:", signature); -})(); -``` diff --git a/snippets/code-snippets/light-token/extensions/token-groups/action.mdx b/snippets/code-snippets/light-token/extensions/token-groups/action.mdx deleted file mode 100644 index 5aeebc5..0000000 --- a/snippets/code-snippets/light-token/extensions/token-groups/action.mdx +++ /dev/null @@ -1,179 +0,0 @@ -```typescript -import "dotenv/config"; -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - ExtensionType, - getMintLen, - createInitializeMint2Instruction, - createInitializeGroupPointerInstruction, - createInitializeGroupInstruction, - createInitializeGroupMemberPointerInstruction, - createInitializeMemberInstruction, -} from "@solana/spl-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 () { - // ===== Step 1: Create a group mint ===== - const groupMintKeypair = Keypair.generate(); - const decimals = 0; - - // Calculate space including GroupPointer and TokenGroup extensions - const groupMintLen = getMintLen([ - ExtensionType.GroupPointer, - ExtensionType.TokenGroup, - ]); - const groupRentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(groupMintLen); - - // Create the group mint account - const createGroupMintIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: groupRentExemptBalance, - newAccountPubkey: groupMintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: groupMintLen, - }); - - // Initialize GroupPointer (points to the mint itself) - const initGroupPointerIx = createInitializeGroupPointerInstruction( - groupMintKeypair.publicKey, - payer.publicKey, // authority - groupMintKeypair.publicKey, // group address (self-referencing) - TOKEN_2022_PROGRAM_ID - ); - - // Initialize the group mint - const initGroupMintIx = createInitializeMint2Instruction( - groupMintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID - ); - - // Initialize the TokenGroup data on the mint - const initGroupIx = createInitializeGroupInstruction({ - group: groupMintKeypair.publicKey, - maxSize: 100, - mint: groupMintKeypair.publicKey, - mintAuthority: payer.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - updateAuthority: payer.publicKey, - }); - - // Register the group mint with Light Token - const registerGroupIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: groupMintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); - - const groupTx = new Transaction().add( - createGroupMintIx, - initGroupPointerIx, - initGroupMintIx, - initGroupIx, - registerGroupIx - ); - - const groupSignature = await sendAndConfirmTransaction(rpc, groupTx, [ - payer, - groupMintKeypair, - ]); - - console.log("Group Mint:", groupMintKeypair.publicKey.toBase58()); - console.log("Group Tx:", groupSignature); - - // ===== Step 2: Create a member mint ===== - const memberMintKeypair = Keypair.generate(); - - // Calculate space including GroupMemberPointer and TokenGroupMember extensions - const memberMintLen = getMintLen([ - ExtensionType.GroupMemberPointer, - ExtensionType.TokenGroupMember, - ]); - const memberRentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(memberMintLen); - - // Create the member mint account - const createMemberMintIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: memberRentExemptBalance, - newAccountPubkey: memberMintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: memberMintLen, - }); - - // Initialize GroupMemberPointer (points to the member mint itself) - const initMemberPointerIx = - createInitializeGroupMemberPointerInstruction( - memberMintKeypair.publicKey, - payer.publicKey, // authority - memberMintKeypair.publicKey, // member address (self-referencing) - TOKEN_2022_PROGRAM_ID - ); - - // Initialize the member mint - const initMemberMintIx = createInitializeMint2Instruction( - memberMintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID - ); - - // Initialize the TokenGroupMember data on the member mint - const initMemberIx = createInitializeMemberInstruction({ - group: groupMintKeypair.publicKey, - groupUpdateAuthority: payer.publicKey, - member: memberMintKeypair.publicKey, - memberMint: memberMintKeypair.publicKey, - memberMintAuthority: payer.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - }); - - // Register the member mint with Light Token - const registerMemberIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: memberMintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); - - const memberTx = new Transaction().add( - createMemberMintIx, - initMemberPointerIx, - initMemberMintIx, - initMemberIx, - registerMemberIx - ); - - const memberSignature = await sendAndConfirmTransaction(rpc, memberTx, [ - payer, - memberMintKeypair, - ]); - - console.log("Member Mint:", memberMintKeypair.publicKey.toBase58()); - console.log("Member Tx:", memberSignature); -})(); -``` diff --git a/snippets/code-snippets/light-token/extensions/transfer-fees/action.mdx b/snippets/code-snippets/light-token/extensions/transfer-fees/action.mdx deleted file mode 100644 index 82cf3f6..0000000 --- a/snippets/code-snippets/light-token/extensions/transfer-fees/action.mdx +++ /dev/null @@ -1,94 +0,0 @@ -```typescript -import "dotenv/config"; -import { - Keypair, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - getMintLen, - createInitializeMint2Instruction, - ExtensionType, - createInitializeTransferFeeConfigInstruction, -} from "@solana/spl-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 () { - const mintKeypair = Keypair.generate(); - const decimals = 9; - - // Calculate space for mint + TransferFeeConfig extension - const mintLen = getMintLen([ExtensionType.TransferFeeConfig]); - const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - - // Instruction 1: Create account - const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, - }); - - // Instruction 2: Initialize TransferFeeConfig with zero fees - // Light Token requires fees to be zero - const initTransferFeeIx = createInitializeTransferFeeConfigInstruction( - mintKeypair.publicKey, - payer.publicKey, // transfer fee config authority - payer.publicKey, // withdraw withheld authority - 0, // fee basis points (must be zero) - BigInt(0), // maximum fee (must be zero) - TOKEN_2022_PROGRAM_ID - ); - - // Instruction 3: Initialize mint - const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID - ); - - // Instruction 4: Create SPL interface PDA - // Holds Token-2022 tokens when wrapped to light-token - const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); - - const tx = new Transaction().add( - createAccountIx, - initTransferFeeIx, - initMintIx, - createSplInterfaceIx - ); - - const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, - ]); - - console.log("Mint:", mintKeypair.publicKey.toBase58()); - console.log("Tx:", signature); -})(); -``` diff --git a/snippets/code-snippets/light-token/extensions/transfer-hook/action.mdx b/snippets/code-snippets/light-token/extensions/transfer-hook/action.mdx deleted file mode 100644 index 4e6237d..0000000 --- a/snippets/code-snippets/light-token/extensions/transfer-hook/action.mdx +++ /dev/null @@ -1,93 +0,0 @@ -```typescript -import "dotenv/config"; -import { - Keypair, - PublicKey, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { createRpc } from "@lightprotocol/stateless.js"; -import { LightTokenProgram } from "@lightprotocol/compressed-token"; -import { - TOKEN_2022_PROGRAM_ID, - getMintLen, - createInitializeMint2Instruction, - ExtensionType, - createInitializeTransferHookInstruction, -} from "@solana/spl-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 () { - const mintKeypair = Keypair.generate(); - const decimals = 9; - - // Calculate space for mint + TransferHook extension - const mintLen = getMintLen([ExtensionType.TransferHook]); - const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(mintLen); - - // Instruction 1: Create account - const createAccountIx = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - lamports: rentExemptBalance, - newAccountPubkey: mintKeypair.publicKey, - programId: TOKEN_2022_PROGRAM_ID, - space: mintLen, - }); - - // Instruction 2: Initialize TransferHook with nil program_id (hook disabled) - // Light Token requires program_id to be nil (PublicKey.default) - const initTransferHookIx = createInitializeTransferHookInstruction( - mintKeypair.publicKey, - payer.publicKey, // authority - PublicKey.default, // program_id must be nil - TOKEN_2022_PROGRAM_ID - ); - - // Instruction 3: Initialize mint - const initMintIx = createInitializeMint2Instruction( - mintKeypair.publicKey, - decimals, - payer.publicKey, // mint authority - null, // freeze authority - TOKEN_2022_PROGRAM_ID - ); - - // Instruction 4: Create SPL interface PDA - // Holds Token-2022 tokens when wrapped to light-token - const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); - - const tx = new Transaction().add( - createAccountIx, - initTransferHookIx, - initMintIx, - createSplInterfaceIx - ); - - const signature = await sendAndConfirmTransaction(rpc, tx, [ - payer, - mintKeypair, - ]); - - console.log("Mint:", mintKeypair.publicKey.toBase58()); - console.log("Tx:", signature); -})(); -``` diff --git a/snippets/code-snippets/light-token/load-ata/instruction.mdx b/snippets/code-snippets/light-token/load-ata/instruction.mdx index cb5b9ea..8608518 100644 --- a/snippets/code-snippets/light-token/load-ata/instruction.mdx +++ b/snippets/code-snippets/light-token/load-ata/instruction.mdx @@ -52,9 +52,11 @@ const payer = Keypair.fromSecretKey( if (ixs.length === 0) return console.log("Nothing to load"); - const blockhash = await rpc.getLatestBlockhash(); - const tx = buildAndSignTx(ixs, payer, blockhash.blockhash); - const signature = await sendAndConfirmTx(rpc, tx); - console.log("Tx:", signature); + for (const batch of ixs) { + const blockhash = await rpc.getLatestBlockhash(); + const tx = buildAndSignTx(batch, payer, blockhash.blockhash); + const signature = await sendAndConfirmTx(rpc, tx); + console.log("Tx:", signature); + } })(); ``` diff --git a/snippets/code-snippets/payments/spend-permissions/delegate-transfer-instruction.mdx b/snippets/code-snippets/payments/spend-permissions/delegate-transfer-instruction.mdx index 818b230..32bf488 100644 --- a/snippets/code-snippets/payments/spend-permissions/delegate-transfer-instruction.mdx +++ b/snippets/code-snippets/payments/spend-permissions/delegate-transfer-instruction.mdx @@ -4,7 +4,7 @@ import { Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; -import { createTransferDelegatedInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; +import { createTransferInterfaceInstructions } from "@lightprotocol/compressed-token/unified"; import { rpc, payer, setup } from "../setup.js"; (async function () { @@ -14,15 +14,15 @@ import { rpc, payer, setup } from "../setup.js"; const recipient = Keypair.generate(); // Returns TransactionInstruction[][]. Each inner array is one txn. - const instructions = await createTransferDelegatedInterfaceInstructions( + const instructions = await createTransferInterfaceInstructions( rpc, payer.publicKey, mint, 200_000, delegate.publicKey, - payer.publicKey, recipient.publicKey, - 9 + 9, + { owner: payer.publicKey } ); for (const ixs of instructions) { diff --git a/snippets/code-snippets/payments/spend-permissions/delegate-transfer.mdx b/snippets/code-snippets/payments/spend-permissions/delegate-transfer.mdx index cf10fdd..ae7ddbc 100644 --- a/snippets/code-snippets/payments/spend-permissions/delegate-transfer.mdx +++ b/snippets/code-snippets/payments/spend-permissions/delegate-transfer.mdx @@ -1,27 +1,44 @@ ```typescript import { Keypair } from "@solana/web3.js"; -import { transferDelegatedInterface } from "@lightprotocol/compressed-token/unified"; +import { + approveInterface, + transferInterface, +} from "@lightprotocol/compressed-token/unified"; import { rpc, payer, setup } from "../setup.js"; (async function () { const { mint, senderAta } = await setup(); - // Approve a delegate first (see delegate-approve.mdx) + // Approve: grant delegate permission to spend up to 500,000 tokens const delegate = Keypair.generate(); - const recipient = Keypair.generate(); + await approveInterface( + rpc, + payer, + senderAta, + mint, + delegate.publicKey, + 500_000, + payer + ); + console.log("Approved delegate:", delegate.publicKey.toBase58()); // Delegate transfers tokens on behalf of the owner - const tx = await transferDelegatedInterface( + const recipient = Keypair.generate(); + const tx = await transferInterface( rpc, payer, senderAta, mint, recipient.publicKey, delegate, - payer.publicKey, - 200_000 + 200_000, + undefined, + undefined, + { owner: payer.publicKey } ); - console.log("Delegated transfer:", tx); + console.log("Delegated transfer to:", recipient.publicKey.toBase58()); + console.log("Amount: 200,000 tokens"); + console.log("Tx:", tx); })(); ``` diff --git a/snippets/extensions-table.mdx b/snippets/extensions-table.mdx index 8a7b1e0..e3bcb04 100644 --- a/snippets/extensions-table.mdx +++ b/snippets/extensions-table.mdx @@ -1,18 +1,18 @@ -| Extension | Description | -|-----------|-------------| -| [MetadataPointer](/light-token/extensions/metadata-and-metadata-pointer) | Points a mint to the account that stores its metadata. | -| [TokenMetadata](/light-token/extensions/metadata-and-metadata-pointer) | Stores token name, symbol, and URI directly on the mint. | -| [TransferFeeConfig](/light-token/extensions/transfer-fees) | Withholds a percentage of each transfer as a fee. | -| [TransferHook](/light-token/extensions/transfer-hook) | Invokes a custom program on every transfer via CPI. | -| [InterestBearingConfig](/light-token/extensions/interest-bearing-tokens) | Displays a UI-adjusted balance that accrues interest over time. | -| [DefaultAccountState](/light-token/extensions/default-account-state) | Sets the initial state (e.g., frozen) for newly created token accounts. | -| [PermanentDelegate](/light-token/extensions/permanent-delegate) | Grants an authority unrestricted transfer and burn rights over all accounts for the mint. | -| [MintCloseAuthority](/light-token/extensions/close-mint) | Allows a designated authority to close a mint account. | -| [GroupPointer](/light-token/extensions/token-groups-and-members) | Points a mint to the account that stores group configuration. | -| [GroupMemberPointer](/light-token/extensions/token-groups-and-members) | Points a mint to the account that stores group member configuration. | -| [TokenGroup](/light-token/extensions/token-groups-and-members) | Stores group configuration directly on the mint (e.g., NFT collections). | -| [TokenGroupMember](/light-token/extensions/token-groups-and-members) | Stores group member configuration directly on the mint. | -| [Pausable](/light-token/extensions/pausable-mint) | Allows an authority to pause all minting, burning, and transfers. | -| [ConfidentialTransferMint](/light-token/extensions/confidential-transfer) | Configures auditor keys for confidential (encrypted) transfers. | -| [ConfidentialTransferFeeConfig](/light-token/extensions/confidential-transfer) | Encrypts withheld transfer fees under an auditor's public key. | -| [ConfidentialMintBurn](/light-token/extensions/confidential-transfer) | Allows minting and burning of tokens with encrypted amounts. | +| Extension | Restriction | Description | Links | +|-----------|-------------|-------------|-------| +| **MetadataPointer** | - | Points a mint to the account that stores its metadata. | [Solana Docs](https://solana.com/developers/guides/token-extensions/metadata-pointer) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/metadata-and-metadata-pointer.ts) | +| **TokenMetadata** | - | Stores token name, symbol, and URI directly on the mint. | [Solana Docs](https://solana.com/developers/guides/token-extensions/metadata-pointer) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/metadata-and-metadata-pointer.ts) | +| **TransferFeeConfig** | Fees must be zero | Withholds a percentage of each transfer as a fee. | [Solana Docs](https://solana.com/developers/guides/token-extensions/transfer-fee) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-fees.ts) | +| **TransferHook** | `program_id` must be nil | Invokes a custom program on every transfer via CPI. | [Solana Docs](https://solana.com/developers/guides/token-extensions/transfer-hook) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-hook.ts) | +| **InterestBearingConfig** | - | Displays a UI-adjusted balance that accrues interest over time. | [Solana Docs](https://solana.com/developers/guides/token-extensions/interest-bearing-tokens) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/interest-bearing-tokens.ts) | +| **DefaultAccountState** | Set `compression_only` flag on token accounts | Sets the initial state (e.g., frozen) for newly created token accounts. | [Solana Docs](https://solana.com/developers/guides/token-extensions/default-account-state) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/default-account-state.ts) | +| **PermanentDelegate** | Set `compression_only` flag on token accounts | Grants an authority unrestricted transfer and burn rights over all accounts for the mint. | [Solana Docs](https://solana.com/developers/guides/token-extensions/permanent-delegate) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/permanent-delegate.ts) | +| **MintCloseAuthority** | Set `compression_only` flag on token accounts | Allows a designated authority to close a mint account. | [Solana Docs](https://solana.com/developers/guides/token-extensions/mint-close-authority) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/close-mint.ts) | +| **GroupPointer** | - | Points a mint to the account that stores group configuration. | [Solana Docs](https://solana.com/developers/guides/token-extensions/group-member) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts) | +| **GroupMemberPointer** | - | Points a mint to the account that stores group member configuration. | [Solana Docs](https://solana.com/developers/guides/token-extensions/group-member) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts) | +| **TokenGroup** | - | Stores group configuration directly on the mint (e.g., NFT collections). | [Solana Docs](https://solana.com/developers/guides/token-extensions/group-member) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts) | +| **TokenGroupMember** | - | Stores group member configuration directly on the mint. | [Solana Docs](https://solana.com/developers/guides/token-extensions/group-member) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts) | +| **Pausable** | Set `compression_only` flag on token accounts | Allows an authority to pause all minting, burning, and transfers. | [Solana Docs](https://solana.com/docs/tokens/extensions/pausable) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/pausable-mint.ts) | +| **ConfidentialTransferMint** | Initialized but not enabled | Configures auditor keys for confidential (encrypted) transfers. | [Solana Docs](https://www.solana-program.com/docs/confidential-balances) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/confidential-transfer.ts) | +| **ConfidentialTransferFeeConfig** | Initialized but not enabled | Encrypts withheld transfer fees under an auditor's public key. | [Solana Docs](https://www.solana-program.com/docs/confidential-balances) | +| **ConfidentialMintBurn** | Initialized but not enabled | Allows minting and burning of tokens with encrypted amounts. | [Solana Docs](https://www.solana-program.com/docs/confidential-balances) | diff --git a/snippets/jsx/stats-widget.jsx b/snippets/jsx/stats-widget.jsx new file mode 100644 index 0000000..514f08f --- /dev/null +++ b/snippets/jsx/stats-widget.jsx @@ -0,0 +1,90 @@ +export const StatsWidget = () => { + const API_URL = "http://localhost:3004/api/metrics"; + const REFRESH_MS = 30000; + const MONO = "ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, monospace"; + + const formatNumber = (value, digits = 2) => + new Intl.NumberFormat("en-US", { + maximumFractionDigits: digits, + }).format(value); + + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(false); + + useEffect(() => { + const controller = new AbortController(); + + async function fetchMetrics() { + try { + const res = await fetch(API_URL, { + signal: controller.signal, + cache: "no-store", + }); + if (!res.ok) throw new Error("fetch failed"); + const json = await res.json(); + setData(json); + setError(false); + } catch (err) { + if (err.name === "AbortError") return; + setError(true); + } finally { + setLoading(false); + } + } + + fetchMetrics(); + const interval = setInterval(fetchMetrics, REFRESH_MS); + return () => { + controller.abort(); + clearInterval(interval); + }; + }, []); + + if (loading) { + return ( +
+
+
+
+
+
+
+
+
+
+ ); + } + + if (error || !data) return null; + + const tps = data.tpsAverages?.tps1h ?? 0; + const txCount = data.totals?.txCountWindow ?? 0; + + return ( +
+
+
+ {formatNumber(tps, 2)} +
+
+ Transactions per Second +
+
+
+
+ {formatNumber(txCount, 0)} +
+
+ Transactions last 24 hours +
+
+
+ ); +}; diff --git a/snippets/overview-tables/light-token-client-examples-table.mdx b/snippets/overview-tables/light-token-client-examples-table.mdx index 53c5906..81dc68e 100644 --- a/snippets/overview-tables/light-token-client-examples-table.mdx +++ b/snippets/overview-tables/light-token-client-examples-table.mdx @@ -12,7 +12,7 @@ | | | | | |---------|--------|-------------|------| -| **approve** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-approve.ts) | — | [Docs](/light-token/cookbook/approve-revoke) | +| **approve** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-approve.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/delegate-approve.ts) | [Docs](/light-token/cookbook/approve-revoke) | | **create-ata** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-ata.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/create-ata.ts) | [Docs](/light-token/cookbook/create-ata) | | **create-ata-explicit-rent-sponsor** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-ata-explicit-rent-sponsor.ts) | — | [Docs](/light-token/cookbook/create-ata) | | **create-mint** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/create-mint.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/create-mint.ts) | [Docs](/light-token/cookbook/create-mint) | @@ -22,7 +22,7 @@ | **delegate-transfer** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-transfer.ts) | — | [Docs](/light-token/cookbook/transfer-delegated) | | **load-ata** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/load-ata.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/load-ata.ts) | [Docs](/light-token/cookbook/load-ata) | | **mint-to** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/mint-to.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/mint-to.ts) | [Docs](/light-token/cookbook/mint-to) | -| **revoke** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-revoke.ts) | — | [Docs](/light-token/cookbook/approve-revoke) | +| **revoke** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/delegate-revoke.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/delegate-revoke.ts) | [Docs](/light-token/cookbook/approve-revoke) | | **transfer-interface** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/transfer-interface.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/transfer-interface.ts) | [Docs](/light-token/cookbook/transfer-interface) | | **unwrap** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/unwrap.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/unwrap.ts) | [Docs](/light-token/cookbook/wrap-unwrap) | | **wrap** | [Action](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/actions/wrap.ts) | [Instruction](https://github.com/Lightprotocol/examples-light-token/blob/main/typescript-client/instructions/wrap.ts) | [Docs](/light-token/cookbook/wrap-unwrap) | @@ -50,15 +50,17 @@ ### Extensions -| | | | -|---------|-------------|------| -| **close-mint** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/close-mint.ts) | [Docs](/light-token/extensions/close-mint) | -| **confidential-transfer** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/confidential-transfer.ts) | [Docs](/light-token/extensions/confidential-transfer) | -| **default-account-state** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/default-account-state.ts) | [Docs](/light-token/extensions/default-account-state) | -| **interest-bearing-tokens** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/interest-bearing-tokens.ts) | [Docs](/light-token/extensions/interest-bearing-tokens) | -| **metadata-and-metadata-pointer** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/metadata-and-metadata-pointer.ts) | [Docs](/light-token/extensions/metadata-and-metadata-pointer) | -| **pausable-mint** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/pausable-mint.ts) | [Docs](/light-token/extensions/pausable-mint) | -| **permanent-delegate** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/permanent-delegate.ts) | [Docs](/light-token/extensions/permanent-delegate) | -| **token-groups-and-members** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts) | [Docs](/light-token/extensions/token-groups-and-members) | -| **transfer-fees** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-fees.ts) | [Docs](/light-token/extensions/transfer-fees) | -| **transfer-hook** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-hook.ts) | [Docs](/light-token/extensions/transfer-hook) | +See how [Light Token works with Token 2022 extensions](/light-token/extensions/overview). + +| | | +|---------|-------------| +| **close-mint** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/close-mint.ts) | +| **confidential-transfer** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/confidential-transfer.ts) | +| **default-account-state** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/default-account-state.ts) | +| **interest-bearing-tokens** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/interest-bearing-tokens.ts) | +| **metadata-and-metadata-pointer** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/metadata-and-metadata-pointer.ts) | +| **pausable-mint** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/pausable-mint.ts) | +| **permanent-delegate** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/permanent-delegate.ts) | +| **token-groups-and-members** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts) | +| **transfer-fees** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-fees.ts) | +| **transfer-hook** | [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-hook.ts) | diff --git a/snippets/setup/extensions-setup.mdx b/snippets/setup/extensions-setup.mdx deleted file mode 100644 index a5ceef7..0000000 --- a/snippets/setup/extensions-setup.mdx +++ /dev/null @@ -1,18 +0,0 @@ - - -```bash -npm install @lightprotocol/compressed-token@beta \ - @lightprotocol/stateless.js@beta \ - @solana/spl-token -``` - -Snippets below assume `rpc`, `payer`, `mint`, `owner`, `recipient`, and `amount` are defined. -See the [full examples](https://github.com/Lightprotocol/examples-light-token/tree/main/extensions) for runnable setup. - -```typescript -import { createRpc } from "@lightprotocol/stateless.js"; - -const rpc = createRpc(RPC_ENDPOINT); -``` - - From 5f6cb123124579f5bf3a593f5c8c397e541fcce5 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Fri, 20 Mar 2026 18:41:32 +0000 Subject: [PATCH 17/19] update --- docs.json | 4 ---- faq.mdx | 2 +- light-token/payments/overview.mdx | 2 +- light-token/payments/verify-payments.mdx | 30 ++---------------------- scripts/copy-code-snippets.sh | 7 ++++-- scripts/copy-light-token-snippets.sh | 7 ++++-- scripts/copy-payments-snippets.sh | 7 ++++-- scripts/copy-privy-snippets.sh | 9 ++++--- scripts/copy-program-snippets.sh | 9 ++++--- scripts/copy-rust-snippets.sh | 7 ++++-- scripts/copy-wallet-adapter-snippets.sh | 7 ++++-- scripts/sync-skills.sh | 7 ++++-- 12 files changed, 46 insertions(+), 52 deletions(-) diff --git a/docs.json b/docs.json index b8132b6..76cf163 100644 --- a/docs.json +++ b/docs.json @@ -353,10 +353,6 @@ } }, "redirects": [ - { - "source": "/pda/compressed-pdas/nullifier-pda", - "destination": "https://zkcompression.com/pda/compressed-pdas/nullifier-pda" - }, { "source": "/light-token/payments/nullifier-pda", "destination": "https://zkcompression.com/pda/compressed-pdas/nullifier-pda" diff --git a/faq.mdx b/faq.mdx index 6190cec..5bc3bdd 100644 --- a/faq.mdx +++ b/faq.mdx @@ -149,7 +149,7 @@ The Light Token SDK covers every SPL Token operation and adds extra capabilities **Unified balance** - `getAtaInterface` returns the Light Token ATA balance for a given mint. To include compressed (cold), SPL, and Token 2022 balances, call `loadAta` first to unify them into the ATA. + `getAtaInterface` returns a unified balance for a given mint, aggregating Light Token (hot + cold), SPL, and Token 2022 sources. **Wrap / Unwrap** diff --git a/light-token/payments/overview.mdx b/light-token/payments/overview.mdx index 9055758..cdf5ae4 100644 --- a/light-token/payments/overview.mdx +++ b/light-token/payments/overview.mdx @@ -80,7 +80,7 @@ The Light Token APIs cover every SPL Token operation and adds extra capabilities **Unified balance** - `getAtaInterface` returns a unified balance for a given mint held in Light Token accounts. With `wrap=true`, it also includes SPL and Token 2022 balances. + `getAtaInterface` returns a unified balance for a given mint, aggregating Light Token (hot + cold), SPL, and Token 2022 sources. **Wrap / Unwrap** diff --git a/light-token/payments/verify-payments.mdx b/light-token/payments/verify-payments.mdx index fc6d6c6..a98bf47 100644 --- a/light-token/payments/verify-payments.mdx +++ b/light-token/payments/verify-payments.mdx @@ -49,9 +49,7 @@ const rpc = createRpc(RPC_ENDPOINT); ## Query balance -### Light Token balance - -Returns the Light Token ATA balance (hot balance). +`getAtaInterface` returns a unified balance aggregating Light Token (hot + cold), SPL, and Token 2022 sources in `parsed.amount`. Find a full code example [here](https://github.com/Lightprotocol/examples-light-token/blob/main/toolkits/payments/verify/get-balance.ts). @@ -66,7 +64,7 @@ import { const ata = getAssociatedTokenAddressInterface(mint, owner); const account = await getAtaInterface(rpc, ata, owner, mint); -console.log(account.parsed.amount); // Light Token ATA balance +console.log(account.parsed.amount); // Unified balance ``` @@ -81,30 +79,6 @@ console.log(account.amount); -### Unified balance - -To include compressed (cold) and optionally SPL/T22 balances, call `loadAta` first to unify everything into the Light Token ATA, then read the balance. - -```typescript -import { - loadAta, - getAssociatedTokenAddressInterface, - getAtaInterface, -} from "@lightprotocol/compressed-token/unified"; - -const ata = getAssociatedTokenAddressInterface(mint, owner); - -// Unify compressed (cold) balances into the Light Token ATA -await loadAta(rpc, ata, payer, mint, payer); - -const account = await getAtaInterface(rpc, ata, owner, mint); -console.log(account.parsed.amount); // Unified balance -``` - - -See the [Load Associated Token Account](/light-token/cookbook/load-ata) guide for details on `loadAta`, including wrapping SPL and Token 2022 balances. - - ## Transaction history diff --git a/scripts/copy-code-snippets.sh b/scripts/copy-code-snippets.sh index d4f3e3f..458ff4b 100755 --- a/scripts/copy-code-snippets.sh +++ b/scripts/copy-code-snippets.sh @@ -3,8 +3,11 @@ # Script to copy code from program-examples to docs/snippets/code-snippets # Wraps each file in appropriate markdown code blocks -PROGRAM_EXAMPLES="/home/tilo/Workspace/program-examples/basic-operations" -SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets" +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROGRAM_EXAMPLES="${PROGRAM_EXAMPLES_ROOT:?Set PROGRAM_EXAMPLES_ROOT to program-examples repo root}/basic-operations" +SNIPPETS_DIR="$SCRIPT_DIR/../snippets/code-snippets" # Operations to process OPERATIONS=("create" "update" "close" "reinit" "burn") diff --git a/scripts/copy-light-token-snippets.sh b/scripts/copy-light-token-snippets.sh index b940786..c86120d 100644 --- a/scripts/copy-light-token-snippets.sh +++ b/scripts/copy-light-token-snippets.sh @@ -3,8 +3,11 @@ # Script to copy TypeScript code from streaming-tokens to docs/snippets/code-snippets/light-token # Wraps each file in typescript markdown code blocks -EXAMPLES="/home/tilo/Workspace/examples-light-token-main/typescript-client" -SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/light-token" +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +EXAMPLES="${EXAMPLES_LIGHT_TOKEN:?Set EXAMPLES_LIGHT_TOKEN to examples-light-token repo root}/typescript-client" +SNIPPETS_DIR="$SCRIPT_DIR/../snippets/code-snippets/light-token" # Recipes to process (matching directory and file names) RECIPES=("create-mint" "create-ata" "mint-to" "transfer-interface" "load-ata" "wrap" "unwrap") diff --git a/scripts/copy-payments-snippets.sh b/scripts/copy-payments-snippets.sh index 2a0afa5..a0fbbe3 100755 --- a/scripts/copy-payments-snippets.sh +++ b/scripts/copy-payments-snippets.sh @@ -3,8 +3,11 @@ # Script to copy TypeScript code from examples-light-token payments to docs snippets. # Wraps each file in typescript markdown code blocks. -EXAMPLES="/home/tilo/Workspace/examples-light-token-main/toolkits/payments" -SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/payments" +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +EXAMPLES="${EXAMPLES_LIGHT_TOKEN:?Set EXAMPLES_LIGHT_TOKEN to examples-light-token repo root}/toolkits/payments" +SNIPPETS_DIR="$SCRIPT_DIR/../snippets/code-snippets/payments" # Function to wrap TypeScript code in markdown wrap_typescript() { diff --git a/scripts/copy-privy-snippets.sh b/scripts/copy-privy-snippets.sh index f74f955..828e08e 100755 --- a/scripts/copy-privy-snippets.sh +++ b/scripts/copy-privy-snippets.sh @@ -4,9 +4,12 @@ # Source: examples-light-token/privy/{nodejs,react} # Output: snippets/code-snippets/privy/{operation}/{nodejs,react}.mdx -NODEJS_SRC="/home/tilo/Workspace/examples-light-token-main/toolkits/sign-with-privy/nodejs/src" -REACT_SRC="/home/tilo/Workspace/examples-light-token-main/toolkits/sign-with-privy/react/src/hooks" -SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/privy" +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +NODEJS_SRC="${EXAMPLES_LIGHT_TOKEN:?Set EXAMPLES_LIGHT_TOKEN to examples-light-token repo root}/toolkits/sign-with-privy/nodejs/src" +REACT_SRC="${EXAMPLES_LIGHT_TOKEN}/toolkits/sign-with-privy/react/src/hooks" +SNIPPETS_DIR="$SCRIPT_DIR/../snippets/code-snippets/privy" # Operations to process OPERATIONS=("transfer" "receive" "wrap" "unwrap" "balances" "transaction-history") diff --git a/scripts/copy-program-snippets.sh b/scripts/copy-program-snippets.sh index 848c48a..475f77c 100644 --- a/scripts/copy-program-snippets.sh +++ b/scripts/copy-program-snippets.sh @@ -3,13 +3,16 @@ # Script to copy program code from example repos to docs snippets # Creates CodeGroup MDX files with lib.rs/instruction.rs and test.rs combined -SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/light-token" +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SNIPPETS_DIR="$SCRIPT_DIR/../snippets/code-snippets/light-token" # ============================================================================= # ANCHOR PROGRAMS # ============================================================================= -ANCHOR_EXAMPLES_DIR="/home/tilo/Workspace/examples-light-token-main/programs/anchor/basic-instructions" +ANCHOR_EXAMPLES_DIR="${EXAMPLES_LIGHT_TOKEN:?Set EXAMPLES_LIGHT_TOKEN to examples-light-token repo root}/programs/anchor/basic-instructions" # Anchor recipes (output-name:anchor-dir-name) # Some have different directory names (e.g., close-token-account uses 'close' dir) @@ -82,7 +85,7 @@ done # ANCHOR MACROS # ============================================================================= -ANCHOR_MACROS_DIR="/home/tilo/Workspace/examples-light-token-main/programs/anchor/basic-macros" +ANCHOR_MACROS_DIR="${EXAMPLES_LIGHT_TOKEN}/programs/anchor/basic-macros" ANCHOR_MACRO_RECIPES=( "create-mint:create-mint" diff --git a/scripts/copy-rust-snippets.sh b/scripts/copy-rust-snippets.sh index b73ecc4..eff19bc 100644 --- a/scripts/copy-rust-snippets.sh +++ b/scripts/copy-rust-snippets.sh @@ -3,8 +3,11 @@ # Script to copy Rust client code from examples-light-token-rust-client to docs snippets # Creates action.mdx and instruction.mdx files wrapped in rust code blocks -EXAMPLES_DIR="/home/tilo/Workspace/examples-light-token-main/rust-client" -SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/light-token" +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +EXAMPLES_DIR="${EXAMPLES_LIGHT_TOKEN:?Set EXAMPLES_LIGHT_TOKEN to examples-light-token repo root}/rust-client" +SNIPPETS_DIR="$SCRIPT_DIR/../snippets/code-snippets/light-token" # Full recipes (action + instruction in same directory) FULL_RECIPES=("create-mint" "mint-to" "transfer-interface" "transfer-checked") diff --git a/scripts/copy-wallet-adapter-snippets.sh b/scripts/copy-wallet-adapter-snippets.sh index 4ffb0ae..cec4fe7 100755 --- a/scripts/copy-wallet-adapter-snippets.sh +++ b/scripts/copy-wallet-adapter-snippets.sh @@ -4,8 +4,11 @@ # Source: examples-light-token/toolkits/sign-with-wallet-adapter/react/src/hooks # Output: snippets/code-snippets/wallet-adapter/{operation}/react.mdx -REACT_SRC="/home/tilo/Workspace/examples-light-token-main/toolkits/sign-with-wallet-adapter/react/src/hooks" -SNIPPETS_DIR="/home/tilo/Workspace/docs-main/snippets/code-snippets/wallet-adapter" +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REACT_SRC="${EXAMPLES_LIGHT_TOKEN:?Set EXAMPLES_LIGHT_TOKEN to examples-light-token repo root}/toolkits/sign-with-wallet-adapter/react/src/hooks" +SNIPPETS_DIR="$SCRIPT_DIR/../snippets/code-snippets/wallet-adapter" # Operations to process OPERATIONS=("transfer" "receive" "wrap" "unwrap" "balances" "transaction-history") diff --git a/scripts/sync-skills.sh b/scripts/sync-skills.sh index 47adac6..c16953f 100755 --- a/scripts/sync-skills.sh +++ b/scripts/sync-skills.sh @@ -1,8 +1,11 @@ #!/bin/bash # Sync skills from agent-skills repo to docs-main/ai-tools/skills -SOURCE="/home/tilo/Workspace/agent-skills/skills" -DEST="/home/tilo/Workspace/docs-main/ai-tools/skills" +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SOURCE="${AGENT_SKILLS_ROOT:?Set AGENT_SKILLS_ROOT to agent-skills repo root}/skills" +DEST="$SCRIPT_DIR/../ai-tools/skills" rsync -av --delete "$SOURCE/" "$DEST/" From bff0b480f9c47c0403d7b20aed71164c4c421af1 Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Fri, 20 Mar 2026 18:53:01 +0000 Subject: [PATCH 18/19] update --- light-token/wallets/gasless-transactions.mdx | 8 +-- .../light-token/load-ata/action.mdx | 2 +- .../light-token/load-ata/instruction.mdx | 2 +- .../code-snippets/privy/receive/nodejs.mdx | 61 +++++++++++++++++++ .../code-snippets/privy/receive/react.mdx | 59 ++++++++++++++++++ .../code-snippets/privy/transfer/react.mdx | 2 +- snippets/code-snippets/privy/unwrap/react.mdx | 2 +- snippets/code-snippets/privy/wrap/react.mdx | 2 +- .../wallet-adapter/receive/react.mdx | 55 +++++++++++++++++ .../wallet-adapter/transfer/react.mdx | 2 +- .../wallet-adapter/unwrap/react.mdx | 2 +- .../wallet-adapter/wrap/react.mdx | 2 +- 12 files changed, 187 insertions(+), 12 deletions(-) diff --git a/light-token/wallets/gasless-transactions.mdx b/light-token/wallets/gasless-transactions.mdx index 3e7bc73..100ad3f 100644 --- a/light-token/wallets/gasless-transactions.mdx +++ b/light-token/wallets/gasless-transactions.mdx @@ -15,8 +15,8 @@ import SupportFooter from "/snippets/support-footer.mdx"; ## Sponsor Top-ups and Transaction Fees -Every Solana transaction requires SOL to pay network fees (around 0.001 USD) and in some cases you need to create a token account (around 0.30 USD with SPL). -Light Token lets your application cover both rent and transaction fees for around 0.001 USD. +Every Solana transaction requires SOL to pay network fees (~$ 0.001) and in some cases you need to create a token account (~$ 0.30 with SPL). +Light Token lets your application cover both rent and transaction fees for around ~$ 0.001. Rent sponsorship is a built-in feature of the Light SDK’s that sponsors rent-exemption for all account types to reduce creation cost. This is dealt with under the hood in a way that doesn’t disrupt the UX of what your users are used to with SPL-token. @@ -36,9 +36,9 @@ Your sponsor covers three costs: | | | | |:-----|:-------|:----| -| **Account creation** | around 11,000 lamports (0.001 USD) | Initial bump on virtual rent balance. Rent-exemption is sponsored. | +| **Account creation** | 11,000 lamports | Initial bump on virtual rent balance. Rent-exemption is sponsored. | | **Rent top-ups** | ~766 lamports per write | Fee payer bumps the virtual rent balance on each write to keep accounts active. Set `payer` parameter on any Light Token instruction. | -| **Transaction fees** | ~5,000 lamports per tx | Standard Solana fee payer. Set `feePayer` on the transaction. | +| **Transaction fees**
+ Priority Fee | 5,000 lamports
+ Priority Fee per tx | Standard Solana fee payer. Set `feePayer` on the transaction. | ## Send a gasless transfer diff --git a/snippets/code-snippets/light-token/load-ata/action.mdx b/snippets/code-snippets/light-token/load-ata/action.mdx index 8f80849..fa1675d 100644 --- a/snippets/code-snippets/light-token/load-ata/action.mdx +++ b/snippets/code-snippets/light-token/load-ata/action.mdx @@ -7,7 +7,7 @@ import { mintToCompressed, loadAta, getAssociatedTokenAddressInterface, -} from "@lightprotocol/compressed-token"; +} from "@lightprotocol/compressed-token/unified"; import { homedir } from "os"; import { readFileSync } from "fs"; diff --git a/snippets/code-snippets/light-token/load-ata/instruction.mdx b/snippets/code-snippets/light-token/load-ata/instruction.mdx index 8608518..7b2c9c7 100644 --- a/snippets/code-snippets/light-token/load-ata/instruction.mdx +++ b/snippets/code-snippets/light-token/load-ata/instruction.mdx @@ -11,7 +11,7 @@ import { mintToCompressed, createLoadAtaInstructions, getAssociatedTokenAddressInterface, -} from "@lightprotocol/compressed-token"; +} from "@lightprotocol/compressed-token/unified"; import { homedir } from "os"; import { readFileSync } from "fs"; diff --git a/snippets/code-snippets/privy/receive/nodejs.mdx b/snippets/code-snippets/privy/receive/nodejs.mdx index 9e21246..4cfeb47 100644 --- a/snippets/code-snippets/privy/receive/nodejs.mdx +++ b/snippets/code-snippets/privy/receive/nodejs.mdx @@ -1,2 +1,63 @@ ```typescript +import 'dotenv/config'; +import {PrivyClient} from '@privy-io/node'; +import {createRpc} from '@lightprotocol/stateless.js'; +import {PublicKey, Transaction} from '@solana/web3.js'; +import { + createLoadAtaInstructions, + getAssociatedTokenAddressInterface, +} from '@lightprotocol/compressed-token/unified'; + +const receiveLightTokens = async ( + recipientAddress: string, + tokenMintAddress: string, +) => { + const connection = createRpc(process.env.HELIUS_RPC_URL!); + + const privy = new PrivyClient({ + appId: process.env.PRIVY_APP_ID!, + appSecret: process.env.PRIVY_APP_SECRET!, + }); + + const recipient = new PublicKey(recipientAddress); + const mintPubkey = new PublicKey(tokenMintAddress); + const ata = getAssociatedTokenAddressInterface(mintPubkey, recipient); + + // Creates the ATA if needed and loads any compressed state into it. + // Returns TransactionInstruction[][] — almost always just one. + const instructions = await createLoadAtaInstructions( + connection, ata, recipient, mintPubkey, recipient, + ); + + // Sign and send each batch via Privy + const walletId = process.env.TREASURY_WALLET_ID!; + const authorizationKey = process.env.TREASURY_AUTHORIZATION_KEY!; + const signatures: string[] = []; + + for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + const {blockhash} = await connection.getLatestBlockhash(); + tx.recentBlockhash = blockhash; + tx.feePayer = recipient; + + const {signed_transaction} = await privy.wallets().solana().signTransaction( + walletId, { + transaction: tx.serialize({requireAllSignatures: false}), + authorization_context: {authorization_private_keys: [authorizationKey]}, + }, + ) as any; + + const sig = await connection.sendRawTransaction( + Buffer.from(signed_transaction, 'base64'), + {skipPreflight: false, preflightCommitment: 'confirmed'}, + ); + await connection.confirmTransaction(sig, 'confirmed'); + signatures.push(sig); + } + + return signatures.length > 0 ? signatures[signatures.length - 1] : null; +}; + +export default receiveLightTokens; + ``` diff --git a/snippets/code-snippets/privy/receive/react.mdx b/snippets/code-snippets/privy/receive/react.mdx index 9e21246..f85e0fd 100644 --- a/snippets/code-snippets/privy/receive/react.mdx +++ b/snippets/code-snippets/privy/receive/react.mdx @@ -1,2 +1,61 @@ ```typescript +import { useState } from 'react'; +import { PublicKey } from '@solana/web3.js'; +import { + createLoadAtaInstructions, + getAssociatedTokenAddressInterface, +} from '@lightprotocol/compressed-token/unified'; +import { createRpc } from '@lightprotocol/stateless.js'; +import type { ConnectedStandardSolanaWallet } from '@privy-io/js-sdk-core'; +import { useSignTransaction } from '@privy-io/react-auth/solana'; +import { signAndSendBatches } from './signAndSendBatches'; + +type SignTransactionFn = ReturnType['signTransaction']; + +export interface ReceiveParams { + ownerPublicKey: string; + mint: string; +} + +export interface ReceiveArgs { + params: ReceiveParams; + wallet: ConnectedStandardSolanaWallet; + signTransaction: SignTransactionFn; +} + +export function useReceive() { + const [isLoading, setIsLoading] = useState(false); + + const receive = async (args: ReceiveArgs): Promise => { + setIsLoading(true); + + try { + const { params, wallet, signTransaction } = args; + + const rpc = createRpc(import.meta.env.VITE_HELIUS_RPC_URL); + + const owner = new PublicKey(params.ownerPublicKey); + const mintPubkey = new PublicKey(params.mint); + const ata = getAssociatedTokenAddressInterface(mintPubkey, owner); + + // Returns TransactionInstruction[][]. + // Each inner array is one transaction. + // Almost always returns just one. + const instructions = await createLoadAtaInstructions( + rpc, ata, owner, mintPubkey, owner, + ); + + return await signAndSendBatches(instructions, { + rpc, + feePayer: owner, + wallet, + signTransaction, + }); + } finally { + setIsLoading(false); + } + }; + + return { receive, isLoading }; +} ``` diff --git a/snippets/code-snippets/privy/transfer/react.mdx b/snippets/code-snippets/privy/transfer/react.mdx index f8ae9b1..e5a3e71 100644 --- a/snippets/code-snippets/privy/transfer/react.mdx +++ b/snippets/code-snippets/privy/transfer/react.mdx @@ -40,7 +40,7 @@ export function useTransfer() { const owner = new PublicKey(ownerPublicKey); const mintPubkey = new PublicKey(mint); const recipient = new PublicKey(toAddress); - const tokenAmount = Math.round(amount * Math.pow(10, decimals)); + const tokenAmount = Math.floor(amount * Math.pow(10, decimals)); // Returns TransactionInstruction[][]. // Each inner array is one transaction. diff --git a/snippets/code-snippets/privy/unwrap/react.mdx b/snippets/code-snippets/privy/unwrap/react.mdx index 0eeafb5..cf5def7 100644 --- a/snippets/code-snippets/privy/unwrap/react.mdx +++ b/snippets/code-snippets/privy/unwrap/react.mdx @@ -39,7 +39,7 @@ export function useUnwrap() { const owner = new PublicKey(ownerPublicKey); const mintPubkey = new PublicKey(mint); - const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); + const tokenAmount = BigInt(Math.floor(amount * Math.pow(10, decimals))); // Auto-detect token program (SPL vs T22) from mint account owner const mintAccountInfo = await rpc.getAccountInfo(mintPubkey); diff --git a/snippets/code-snippets/privy/wrap/react.mdx b/snippets/code-snippets/privy/wrap/react.mdx index 8262a39..4cefafd 100644 --- a/snippets/code-snippets/privy/wrap/react.mdx +++ b/snippets/code-snippets/privy/wrap/react.mdx @@ -41,7 +41,7 @@ export function useWrap() { const owner = new PublicKey(ownerPublicKey); const mintPubkey = new PublicKey(mint); - const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); + const tokenAmount = BigInt(Math.floor(amount * Math.pow(10, decimals))); // Get SPL interface info — determines whether mint uses SPL or T22 const splInterfaceInfos = await getSplInterfaceInfos(rpc, mintPubkey); diff --git a/snippets/code-snippets/wallet-adapter/receive/react.mdx b/snippets/code-snippets/wallet-adapter/receive/react.mdx index 9e21246..1c3e9b7 100644 --- a/snippets/code-snippets/wallet-adapter/receive/react.mdx +++ b/snippets/code-snippets/wallet-adapter/receive/react.mdx @@ -1,2 +1,57 @@ ```typescript +import { useState } from 'react'; +import { PublicKey } from '@solana/web3.js'; +import { + createLoadAtaInstructions, + getAssociatedTokenAddressInterface, +} from '@lightprotocol/compressed-token/unified'; +import { createRpc } from '@lightprotocol/stateless.js'; +import { signAndSendBatches, type SignTransactionFn } from './signAndSendBatches'; + +export interface ReceiveParams { + ownerPublicKey: string; + mint: string; +} + +export interface ReceiveArgs { + params: ReceiveParams; + signTransaction: SignTransactionFn; +} + +export function useReceive() { + const [isLoading, setIsLoading] = useState(false); + + const receive = async (args: ReceiveArgs): Promise => { + setIsLoading(true); + + try { + const { params, signTransaction } = args; + + const rpc = import.meta.env.VITE_LOCALNET === 'true' + ? createRpc() + : createRpc(import.meta.env.VITE_HELIUS_RPC_URL); + + const owner = new PublicKey(params.ownerPublicKey); + const mintPubkey = new PublicKey(params.mint); + const ata = getAssociatedTokenAddressInterface(mintPubkey, owner); + + // Returns TransactionInstruction[][]. + // Each inner array is one transaction. + // Almost always returns just one. + const instructions = await createLoadAtaInstructions( + rpc, ata, owner, mintPubkey, owner, + ); + + return await signAndSendBatches(instructions, { + rpc, + feePayer: owner, + signTransaction, + }); + } finally { + setIsLoading(false); + } + }; + + return { receive, isLoading }; +} ``` diff --git a/snippets/code-snippets/wallet-adapter/transfer/react.mdx b/snippets/code-snippets/wallet-adapter/transfer/react.mdx index c0d635f..8b4deb4 100644 --- a/snippets/code-snippets/wallet-adapter/transfer/react.mdx +++ b/snippets/code-snippets/wallet-adapter/transfer/react.mdx @@ -35,7 +35,7 @@ export function useTransfer() { const owner = new PublicKey(ownerPublicKey); const mintPubkey = new PublicKey(mint); const recipient = new PublicKey(toAddress); - const tokenAmount = Math.round(amount * Math.pow(10, decimals)); + const tokenAmount = Math.floor(amount * Math.pow(10, decimals)); // Returns TransactionInstruction[][]. // Each inner array is one transaction. diff --git a/snippets/code-snippets/wallet-adapter/unwrap/react.mdx b/snippets/code-snippets/wallet-adapter/unwrap/react.mdx index 9588eaf..6ffead4 100644 --- a/snippets/code-snippets/wallet-adapter/unwrap/react.mdx +++ b/snippets/code-snippets/wallet-adapter/unwrap/react.mdx @@ -34,7 +34,7 @@ export function useUnwrap() { const owner = new PublicKey(ownerPublicKey); const mintPubkey = new PublicKey(mint); - const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); + const tokenAmount = BigInt(Math.floor(amount * Math.pow(10, decimals))); // Auto-detect token program (SPL vs T22) from mint account owner const mintAccountInfo = await rpc.getAccountInfo(mintPubkey); diff --git a/snippets/code-snippets/wallet-adapter/wrap/react.mdx b/snippets/code-snippets/wallet-adapter/wrap/react.mdx index 37f4524..a249e19 100644 --- a/snippets/code-snippets/wallet-adapter/wrap/react.mdx +++ b/snippets/code-snippets/wallet-adapter/wrap/react.mdx @@ -37,7 +37,7 @@ export function useWrap() { const owner = new PublicKey(ownerPublicKey); const mintPubkey = new PublicKey(mint); - const tokenAmount = BigInt(Math.round(amount * Math.pow(10, decimals))); + const tokenAmount = BigInt(Math.floor(amount * Math.pow(10, decimals))); // Get SPL interface info — determines whether mint uses SPL or T22 const splInterfaceInfos = await getSplInterfaceInfos(rpc, mintPubkey); From 48f3231f30fd61205b9c70199bccc631f468250b Mon Sep 17 00:00:00 2001 From: tilo-14 Date: Fri, 20 Mar 2026 19:07:39 +0000 Subject: [PATCH 19/19] update --- light-token/wallets/gasless-transactions.mdx | 23 +++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/light-token/wallets/gasless-transactions.mdx b/light-token/wallets/gasless-transactions.mdx index 100ad3f..d898332 100644 --- a/light-token/wallets/gasless-transactions.mdx +++ b/light-token/wallets/gasless-transactions.mdx @@ -15,10 +15,8 @@ import SupportFooter from "/snippets/support-footer.mdx"; ## Sponsor Top-ups and Transaction Fees -Every Solana transaction requires SOL to pay network fees (~$ 0.001) and in some cases you need to create a token account (~$ 0.30 with SPL). -Light Token lets your application cover both rent and transaction fees for around ~$ 0.001. - -Rent sponsorship is a built-in feature of the Light SDK’s that sponsors rent-exemption for all account types to reduce creation cost. + +Rent sponsorship is a built-in feature of the Light SDK’s that sponsors rent-exemption. This is dealt with under the hood in a way that doesn’t disrupt the UX of what your users are used to with SPL-token. @@ -26,19 +24,28 @@ This is dealt with under the hood in a way that doesn’t disrupt the UX of what Solana transactions have a designated fee payer, the account that pays the network fee. By default, this is the first signer. You can specify a different account as the fee payer, allowing a third party (the "sponsor") to -cover fees on behalf of the sender. +cover fees on behalf of the sender. -Light Token extends this further. The `payer` parameter on any Light Token +Light Token extends this: The `payer` parameter on any Light Token instruction determines who pays rent top-ups in addition to transaction fees. -Set your application server as the payer so users never interact with SOL. +Set your application as the payer so users never interact with SOL. -Your sponsor covers three costs: +In total, your sponsor covers three costs: | | | | |:-----|:-------|:----| | **Account creation** | 11,000 lamports | Initial bump on virtual rent balance. Rent-exemption is sponsored. | | **Rent top-ups** | ~766 lamports per write | Fee payer bumps the virtual rent balance on each write to keep accounts active. Set `payer` parameter on any Light Token instruction. | | **Transaction fees**
+ Priority Fee | 5,000 lamports
+ Priority Fee per tx | Standard Solana fee payer. Set `feePayer` on the transaction. | + + +| | Light | SPL / Token 2022 | +| :--- | :--- | :--- | +| **Transfer** | *~\$0.001* | *~\$0.001* | +| **Create Token Account** | **~\$0.001** (0.00001 SOL) | **~\$0.30** (0.0029 SOL) | +| **Transfer + Create Token Account** | **~\$0.001** (0.00001 SOL) | **~\$0.30** (0.0029 SOL) | + + ## Send a gasless transfer