Skip to main content
  1. light-token follows the same API patterns like ATA
  2. Your users hold and receive the same tokens, just stored more efficiently.
Creation CostSPLlight-token
Token Account~2,000,000 lamports~17,000 lamports

What you will implement

light-tokenSPL Token
Get/Create ATAgetOrCreateAtaInterface()getOrCreateAssociatedTokenAccount()
Derive ATAgetAssociatedTokenAddressInterface()getAssociatedTokenAddress()
TransfertransferInterface()transferChecked()
Get BalancegetAtaInterface()getAccount()
Tx Historyrpc.getSignaturesForOwnerInterface()getSignaturesForAddress()
Exit to SPLunwrap()N/A

Setup

npm install @lightprotocol/compressed-token/
            @lightprotocol/stateless.js
import { createRpc } from "@lightprotocol/stateless.js";

import {
  getOrCreateAtaInterface,
  getAtaInterface,
  getAssociatedTokenAddressInterface,
  transferInterface,
  unwrap,
} from "@lightprotocol/compressed-token";

const rpc = createRpc(RPC_ENDPOINT);

Receive Payments

import { getOrCreateAtaInterface } from "@lightprotocol/compressed-token";

const ata = await getOrCreateAtaInterface(
  rpc,
  payer,
  mint,
  recipient
);
// Share ata.parsed.address with sender

console.log(ata.parsed.amount);
import { getOrCreateAssociatedTokenAccount } from "@solana/spl-token";

const ata = await getOrCreateAssociatedTokenAccount(
  connection,
  payer,
  mint,
  recipient
);
// Share ata.address with sender

console.log(ata.amount);

Send Payments

import {
  getAssociatedTokenAddressInterface,
  transferInterface,
} from "@lightprotocol/compressed-token";

const sourceAta = getAssociatedTokenAddressInterface(mint, owner.publicKey);
const destinationAta = getAssociatedTokenAddressInterface(mint, recipient);

await transferInterface(
  rpc,
  payer,
  sourceAta,
  mint,
  destinationAta,
  owner,
  amount
);
To ensure your recipient’s ATA exists you can prepend an idempotent creation instruction in the same atomic transaction:
import {
  getAssociatedTokenAddressInterface,
  createAssociatedTokenAccountInterfaceIdempotentInstruction,
} from "@lightprotocol/compressed-token";
import { CTOKEN_PROGRAM_ID } from "@lightprotocol/stateless.js";

const destinationAta = getAssociatedTokenAddressInterface(mint, recipient);
const createAtaIx = createAssociatedTokenAccountInterfaceIdempotentInstruction(
  payer.publicKey,
  destinationAta,
  recipient,
  mint,
  CTOKEN_PROGRAM_ID
);

new Transaction().add(createAtaIx, transferIx);
import { transfer } from "@solana/spl-token";

const sourceAta = getAssociatedTokenAddressSync(mint, owner.publicKey);
const destinationAta = getAssociatedTokenAddressSync(mint, recipient);

await transfer(
  connection,
  payer,
  sourceAta,
  destinationAta,
  owner,
  amount,
  decimals
);
With idempotent ATA creation:
import {
  getAssociatedTokenAddressSync,
  createAssociatedTokenAccountIdempotentInstruction,
} from "@solana/spl-token";

const destinationAta = getAssociatedTokenAddressSync(mint, recipient);
const createAtaIx = createAssociatedTokenAccountIdempotentInstruction(
  payer.publicKey,
  destinationAta,
  recipient,
  mint
);

new Transaction().add(createAtaIx, transferIx);

Show Balance

import {
  getAssociatedTokenAddressInterface,
  getAtaInterface,
} from "@lightprotocol/compressed-token";

const ata = getAssociatedTokenAddressInterface(mint, owner);
const account = await getAtaInterface(
  rpc,
  ata,
  owner,
  mint
);

console.log(account.parsed.amount);
import { getAccount } from "@solana/spl-token";

const account = await getAccount(connection, ata);

console.log(account.amount);

Transaction History

Token accounts are compressed when inactive
const result = await rpc.getSignaturesForOwnerInterface(owner);

console.log(result.signatures);
console.log(result.solana);
console.log(result.compressed);
Use getSignaturesForAddressInterface(address) if you want address-specific rather than owner-wide history.
const signatures = await connection.getSignaturesForAddress(ata);

Unwrap to SPL

When users need SPL tokens (CEX withdrawal, legacy integration):
import { getAssociatedTokenAddressSync } from "@solana/spl-token";

// SPL ATA must exist
const splAta = getAssociatedTokenAddressSync(mint, owner.publicKey);

await unwrap(
  rpc,
  payer,
  owner,
  mint,
  splAta,
  amount
);