Solana Tracker LogoSolana Tracker
Swap
Developers
⌘K
Affiliate
All Resources
Solana Address Lookup Table RPC: Find and Pick LUTs
UpdatesJSON-RPCJune 4, 20265 min readUpdated October 7, 2026Solana Tracker

Solana Address Lookup Table RPC: Find and Pick LUTs

Solana address lookup table RPC methods find existing LUTs by account, mint or authority, and bestSet picks tables that cover a transaction's accounts.

  • updates,
  • solana-rpc,
  • lookup-tables,
  • versioned-transactions
Solana RPC›Raptor Swap API›

The Solana address lookup table RPC methods on Solana Tracker find existing lookup tables (LUTs) that already contain your transaction's accounts, so a versioned transaction can reference them by one-byte index instead of 32-byte keys. getLookupTablesByAccounts with bestSet: true goes further and picks a small covering set for the whole account list.

Solana address lookup table RPC methods

Each method costs 1 credit per call and pages with limit (default 100, max 1000) and cursor.

MethodKey paramsUse it to
getLookupTablesByAuthorityauthority, mintsOnly, includeDeactivatedInspect the tables a wallet controls
getLookupTablesByAccountaccount, ownerFind tables containing one address
getLookupTablesByMintmint, ownerSame lookup, keyed by token mint
getLookupTablesByAccountsaccounts, owner, bestSetTables containing all accounts, or a covering set

Without these methods you would create and extend your own tables (paying rent and waiting for activation) or scan lookup table accounts yourself. Stock RPC nodes return -32601 Method not found for them. If you only need swaps, Raptor Swap API returns addressLookupTableAddresses alongside its swap instructions.

Intersection mode versus bestSet

With bestSet false (the default), getLookupTablesByAccounts returns tables that contain every account you pass. That is strict: one missing account excludes a table. With bestSet: true it runs a greedy selection across tables and returns the set that covers the most accounts, bounded by:

OptionDefaultEffect
maxLookupTables8Cap on tables in the returned set
candidateLimit5000Cap on candidate tables considered
perAccountLimit500Cap on candidates gathered per account

Greedy means good, not proven minimal. Start with the defaults and tune only after measuring coverage and request time.

Pick tables for a transaction

Pass the accounts your instructions reference. The script needs Node 20+ and tsx; set SOLANA_RPC_URL (full URL including ?api_key=) and optionally ACCOUNTS, then run node --env-file=.env --import tsx lut.ts.

// lut.ts: pick lookup tables that cover a transaction's accounts with bestSet
export {}; // ES module, so top-level await type-checks

const RPC_URL = process.env.SOLANA_RPC_URL?.trim() ?? "";
if (!RPC_URL || !URL.canParse(RPC_URL)) {
  // never print the URL: it contains the key
  console.error("Set SOLANA_RPC_URL to the full URL from https://www.solanatracker.io/account/shared-rpc");
  process.exit(1);
}

const BASE58 = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
const DEFAULT_ACCOUNTS = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v,So11111111111111111111111111111111111111112";
const accounts = [...new Set((process.env.ACCOUNTS ?? DEFAULT_ACCOUNTS).split(",").map((a) => a.trim()).filter(Boolean))];
if (accounts.length === 0 || accounts.some((a) => !BASE58.test(a))) {
  console.error("ACCOUNTS must be comma-separated base58 addresses");
  process.exit(1);
}

type Lut = { pubkey: string; matchedAccounts: string[]; matchedAddressIndices: number[]; estimatedBytesSaved: number };
type BestSet = { lookupTables: Lut[]; coveredAccounts: string[]; uncoveredAccounts: string[]; estimatedBytesSaved: number };
type RpcBody = { result?: BestSet; error?: { code: number; message: string } };

try {
  const res = await fetch(RPC_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: 1,
      method: "getLookupTablesByAccounts",
      params: [{ accounts, bestSet: true, maxLookupTables: 4 }],
    }),
    signal: AbortSignal.timeout(10_000),
  });
  if (res.status === 429) throw new Error("Rate limited (HTTP 429)");
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const body = (await res.json()) as RpcBody;
  if (body.error) throw new Error(`RPC error ${body.error.code}: ${body.error.message}`);
  if (!body.result) throw new Error("Response had no result");

  const { lookupTables, coveredAccounts, uncoveredAccounts, estimatedBytesSaved } = body.result;
  console.table(lookupTables.map((t) => ({ table: t.pubkey, covers: t.matchedAccounts.length, indices: t.matchedAddressIndices.join(" "), bytesSaved: t.estimatedBytesSaved })));
  console.log(`covered ${coveredAccounts.length}/${accounts.length}, estimated bytes saved ${estimatedBytesSaved}`);
  if (uncoveredAccounts.length > 0) console.log("keep as static keys:", uncoveredAccounts.join(", "));
} catch (error) {
  console.error(error instanceof Error && error.name === "TimeoutError" ? "Request timed out after 10s" : String(error));
  process.exit(1);
}

Response shape

The result sits directly under result, with no context wrapper:

{
  "lookupTables": [
    {
      "pubkey": "LUT1...",
      "matchedAccounts": ["AccountA...", "AccountB..."],
      "matchedAddressIndices": [3, 17],
      "estimatedBytesSaved": 62
    }
  ],
  "coveredAccounts": ["AccountA...", "AccountB..."],
  "uncoveredAccounts": ["AccountC..."],
  "estimatedBytesSaved": 62,
  "count": 1
}

Full table entries also carry authority, deactivationSlot, addressCount, addresses, mints, slot and addressIndex. A deactivationSlot of 18446744073709551615 means the table is active. List responses add nextCursor and hasMore.

Pitfalls

  • Trusting the estimate. estimatedBytesSaved is a planning signal. Compile the message, check its size and simulate.
  • Dropping uncovered accounts. Keep uncoveredAccounts as static keys. Signers and invoked program IDs are always static.
  • Unknown authorities. An authority can extend or deactivate its table. Use owner to limit results to authorities you trust.
  • Stale caches. Fetch the table accounts before compiling; the compiler needs current table state, not only a pubkey.
  • Stopping at page one. Follow nextCursor while hasMore is true.

Lookup tables matter most on latency-sensitive paths; see reduce Solana RPC latency and the Solana RPC providers guide. The methods run on Solana RPC shared plans.

FAQ

Does bestSet return the smallest possible set?

No. It is a greedy selection. Check coveredAccounts and uncoveredAccounts.

What is the difference between ByAccount and ByMint?

None in behavior. getLookupTablesByMint is the same lookup with the parameter named mint.

Are deactivated tables returned?

getLookupTablesByAuthority excludes them unless includeDeactivated is true. Check deactivationSlot on any result before use.

What does a call cost?

One credit per call for all four methods.

References

  • Lookup tables guide
  • getLookupTablesByAccounts
  • getLookupTablesByAccount
  • getLookupTablesByMint
  • getLookupTablesByAuthority
  • Raptor swap instructions

Related Guides

Solana SNS RPC: Primary .sol Names in One Call
Updates

Solana SNS RPC: Primary .sol Names in One Call

Read more
Solana Tracker Data API SDK 0.5: Migration Notes
Updates

Solana Tracker Data API SDK 0.5: Migration Notes

Read more
Solana RPC Providers: How to Evaluate and Choose
Solana RPC

Solana RPC Providers: How to Evaluate and Choose

Read more

Products

  • Data API
  • Pump.fun API
  • Solana RPC
  • Dedicated Nodes
  • Yellowstone gRPC
  • Raptor Swap API
  • Enterprise

Trading

  • Swap
  • Latest Tokens
  • Trending
  • Top Gainers
  • Memescope
  • Whale Watch
  • KOL Tracker

Tools

  • Wallet Tracker
  • Rugcheck
  • PnL Leaderboard
  • KOLScan
  • Axiom Leaderboard
  • Photon Leaderboard
  • Bloom Leaderboard
  • FOMO Leaderboard
  • GMGN Leaderboard
  • Pump.fun App Leaderboard
  • Terminal Leaderboard
  • Platform Compare
  • My Positions
  • Teams

Resources

  • Developer Guides
  • Blog
  • Documentation
  • API Reference
  • Status
  • Affiliate Program — 25% recurring, uncapped
Solana TrackerSolana Tracker© 2026
Terms of ServicePrivacy PolicyContact