diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 8137d8c..a00c017 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -1,19 +1,26 @@ name: Setup Environment -description: Setup Rust, Solana CLI, and Light CLI for testing +description: Setup Rust, Solana CLI, and optionally Node.js for testing inputs: + example: + description: "Example directory path" + required: true solana-cli-version: description: "Solana CLI version" required: false - default: "2.1.21" + default: "2.3.11" rust-toolchain: description: "Rust toolchain version" required: false - default: "1.85.0" + default: "1.90.0" light-cli-version: description: "Light CLI version" required: false default: "alpha" + photon-indexer: + description: "Install Photon indexer (required for TypeScript tests)" + required: false + default: "false" runs: using: composite @@ -22,18 +29,20 @@ runs: uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: ${{ inputs.rust-toolchain }} - cache: false + rustflags: "" + cache-workspaces: ${{ inputs.example || '.' }} - - name: Setup Node.js (for Light CLI) + - name: Setup Node.js + if: inputs.node-version != '' uses: actions/setup-node@v4 with: - node-version: "22" + node-version: ${{ inputs.node-version }} - - name: Cache npm global packages - uses: actions/cache@v4 + - name: Setup Node.js (for Light CLI) + if: inputs.node-version == '' + uses: actions/setup-node@v4 with: - path: ~/.npm - key: npm-${{ runner.os }}-light-cli-${{ inputs.light-cli-version }} + node-version: "22" - name: Cache Solana CLI tools uses: actions/cache@v4 @@ -41,7 +50,7 @@ runs: path: | ~/.cache/solana/ ~/.local/share/solana/ - key: solana-cli-${{ runner.os }}-${{ inputs.solana-cli-version }} + key: solana-cli-${{ runner.os }}-build-${{ inputs.solana-cli-version }} - name: Install Solana CLI tools shell: bash @@ -53,6 +62,21 @@ runs: shell: bash run: npm install -g @lightprotocol/zk-compression-cli@${{ inputs.light-cli-version }} + - name: Cache Photon indexer + if: inputs.photon-indexer == 'true' + id: cache-photon + uses: actions/cache@v4 + with: + path: ~/.cargo/bin/photon + key: photon-${{ runner.os }}-ac7df6c388db847b7693a7a1cb766a7c9d7809b5 + + - name: Install Photon indexer + if: inputs.photon-indexer == 'true' && steps.cache-photon.outputs.cache-hit != 'true' + shell: bash + env: + RUSTFLAGS: "-A dead-code" + run: cargo install --git https://github.com/lightprotocol/photon.git --rev ac7df6c388db847b7693a7a1cb766a7c9d7809b5 --locked --force + - name: Generate keypair shell: bash run: solana-keygen new --no-bip39-passphrase @@ -64,4 +88,3 @@ runs: cargo --version solana --version light --version - diff --git a/.gitignore b/.gitignore index 8563720..ea6b209 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,27 @@ +# Dependencies **/node_modules/ **/dist/ + +# Environment and secrets **/.env +**/.env.* +**/*-keypair.json +**/id.json + +# Build artifacts +**/target +**/.anchor + +# Test artifacts +**/test-ledger + +# Lock files **/pnpm-lock.yaml **/package-lock.json + +# Backups **/*.json.bak -**/test-ledger -**/target -cli/accounts -README.html -README_files/ -**/.surfpool -.surfpool \ No newline at end of file +# Project-specific +cli/accounts/ +bugs.md diff --git a/CLAUDE.md b/CLAUDE.md index 672c9ff..448f225 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,209 +2,76 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. -## Project overview +## What this repo is -Light Token examples repository demonstrating rent-free token operations on Solana. Light Token reduces mint and token account costs by 200x through sponsored rent-exemption. +Light Token example programs demonstrating rent-free token vaults using Light Protocol on Solana. Contains Anchor programs (escrow, fundraiser, token-swap, light-token-minter), a shared test utilities crate, TypeScript client examples, and toolkits (payments, streaming). -## Build and test commands +## Build and test -### TypeScript client +All Anchor programs live in `programs/anchor/` as a Cargo workspace. Build and test from that directory: ```bash -# Install dependencies (from repo root — npm workspaces) -npm install - -# Run from typescript-client directory -cd typescript-client -npm run test:actions # Run all action examples (chained sequentially) -npm run test:instructions # Run all instruction examples (chained sequentially) - -# Individual examples (pattern: :) -npm run create-mint:action # Create light-token mint -npm run create-mint:instruction # Create mint with manual instruction building -npm run transfer-interface:action # Transfer between account types -npm run wrap:action # Wrap SPL/T22 to light-token -npm run unwrap:action # Unwrap light-token to SPL/T22 -npm run load-ata:action # Load compressed tokens into light ATA -npm run delegate:approve # Approve delegate -npm run delegate:revoke # Revoke delegate - -# All examples require a running validator — see "Local development" below -``` - -### Rust client - -```bash -cd rust-client -cargo run --example action_create_mint -cargo run --example action_transfer_interface -cargo run --example instruction_transfer_interface -``` - -### Anchor programs - -```bash -cd programs/anchor - -anchor build - -# Test single program (recommended — must use single thread) -cargo test-sbf -p -- --test-threads=1 +# Build a single program +cd programs/anchor && cargo build-sbf --manifest-path escrow/Cargo.toml -# Package names: light-token-anchor-transfer-interface, light-token-anchor-mint-to, -# counter, create-and-transfer -``` - -### Privy Node.js (devnet) - -```bash -cd toolkits/sign-with-privy/nodejs -npm install -cp .env.example .env # fill in Privy credentials + Helius RPC URL - -# App operations (Privy-signed server wallet) -npm run transfer # Light-token ATA → ATA transfer (auto-loads cold balance) -npm run wrap # SPL/T22 → light-token ATA -npm run unwrap # Light-token ATA → SPL/T22 -npm run load # Consolidate cold + SPL + T22 into light-token ATA -npm run light-balance # Query Light Token balance (hot, cold, unified) for TEST_MINT -npm run balances # Query balance breakdown (hot, cold, SPL/T22, SOL) -npm run history # Transaction history for light-token interface ops - -# Setup helpers live in toolkits/sign-with-privy/scripts/ (separate workspace, uses local keypair) -cd ../scripts -npm run mint:spl-and-wrap # Create mint + interface PDA + fund treasury -npm run mint:spl # Mint SPL/T22 tokens to existing mint -npm run register:spl-interface # Register interface PDA on existing mint -``` +# Test a single program (runs LiteSVM-based tests, no validator needed) +cd programs/anchor && cargo test-sbf -p escrow +cd programs/anchor && cargo test-sbf -p fundraiser +cd programs/anchor && cargo test-sbf -p light-token-minter +cd programs/anchor && cargo test-sbf -p swap_example -### Privy React (devnet — WIP) +# Run a single test by name +cd programs/anchor && cargo test-sbf -p escrow -- test_escrow_spl -```bash -cd toolkits/sign-with-privy/react -npm install -cp .env.example .env # fill in VITE_PRIVY_APP_ID and VITE_HELIUS_RPC_URL - -npm run dev # Vite dev server -npm run build # Production build +# TypeScript client examples +cd typescript-client && npm install && npm run create-mint:action ``` -### Local development - -```bash -# Start test validator with Light programs (requires light CLI) -light test-validator - -# Validator health check -curl http://127.0.0.1:8784/health -``` +CI runs `cargo test-sbf -p ` for each program (see `.github/workflows/rust-tests.yml`). Solana CLI 2.3.11, Rust 1.90.0. ## Architecture -### Workspace layout - -Root `package.json` defines npm workspaces: `typescript-client`, `toolkits/payments-and-wallets`, `toolkits/sign-with-privy/nodejs`, `toolkits/sign-with-privy/react`, and `toolkits/sign-with-privy/scripts`. Dependencies are hoisted to root. - -- `typescript-client/` — Core examples: `actions/` (high-level) and `instructions/` (low-level) -- `rust-client/` — Rust client examples as cargo examples -- `programs/anchor/` — On-chain Anchor programs - - `basic-macros/` — Declarative `#[light_account]` macro pattern - - `basic-instructions/` — Explicit CPI calls to light-token program - - `create-and-transfer/` — Combined macro + CPI example -- `toolkits/` — Domain-specific implementations - - `payments-and-wallets/` — Wallet integration patterns (uses `@lightprotocol/compressed-token/unified` subpath) - - `streaming-tokens/` — Laserstream-based token indexing - - `sign-with-privy/` — Privy wallet integration examples (devnet) - - `nodejs/` — Server-side scripts using `@privy-io/node` with server wallet signing - - `react/` — Browser app using `@privy-io/react-auth` with embedded wallet signing (WIP) - -### TypeScript: actions vs instructions - -Every example exists at two abstraction levels: - -**Actions** (`typescript-client/actions/`): Call high-level SDK functions that build, sign, and send transactions in one call. Functions like `createMintInterface`, `transferInterface`, `wrap` return a transaction signature directly. - -**Instructions** (`typescript-client/instructions/`): Build `TransactionInstruction` objects manually, assemble into `Transaction`, and call `sendAndConfirmTransaction`. Requires fetching tree info and validity proofs yourself: -- `getBatchAddressTreeInfo()` — address tree for new account creation -- `selectStateTreeInfo(await rpc.getStateTreeInfos())` — state tree selection -- `rpc.getValidityProofV2([], [{address, treeInfo}])` — ZK validity proof -- `ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 })` — required CU budget - -### Boilerplate pattern - -Every TypeScript example follows the same setup: - -```typescript -import "dotenv/config"; -import { createRpc } from "@lightprotocol/stateless.js"; - -// localnet (default — no args): -const rpc = createRpc(); -// devnet: -// const rpc = createRpc(`https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`); - -// Payer from local Solana keypair: -const payer = Keypair.fromSecretKey( - new Uint8Array(JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8"))) -); -``` - -### Token flow concepts - -- **Light-token ATA**: Associated token account derived via `getAssociatedTokenAddressInterface(mint, owner)`. Created with `createAtaInterface` or `createAtaInterfaceIdempotent`. -- **Wrap**: SPL/T22 tokens → light-token ATA. Requires SPL interface PDA registered via `createSplInterface`. -- **Unwrap**: Light-token ATA → SPL/T22 tokens. -- **Load ATA**: Compressed tokens (cold storage) → light-token ATA (hot balance). Uses `loadAta` action or `createLoadAtaInstructions` + `buildAndSignTx`/`sendAndConfirmTx`. -- **Decompress**: Light-token ATA → SPL T22 account. Used as setup step before wrapping. - -### Two on-chain patterns (Anchor programs) - -**Macro pattern** (`basic-macros/`): Declarative `#[light_account(init)]` attribute and `LightAccounts` derive macro. - -**CPI pattern** (`basic-instructions/`): Explicit CPI calls like `TransferInterfaceCpi`. - -### Privy Node.js architecture (`toolkits/sign-with-privy/nodejs/`) - -Server-side scripts that sign transactions via Privy's wallet API instead of a local keypair. Each script in `src/` is standalone and runnable with `tsx`. All scripts target **devnet**. +### Programs (`programs/anchor/`) -**Script pattern**: Each file exports a reusable async function AND has a `// --- main ---` block at the bottom that imports config values and runs it. Scripts are both importable as modules and directly runnable via `npm run