@wuwei-labs/srsly
Version:
TypeScript SDK for SRSLY
141 lines • 4.89 kB
JavaScript
;
/**
* @purpose Address Lookup Table utilities for SRSLY
*
* Provides helpers for fetching and using the SRSLY Address Lookup Table
* to reduce transaction size for rental operations.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetchLookupTable = fetchLookupTable;
exports.getLookupTableAddress = getLookupTableAddress;
const config_1 = require("../accounts/config");
const rpc_1 = require("./rpc");
const config_2 = require("./config");
/**
* System program address used as default when ALT not configured
*/
const SYSTEM_PROGRAM_ID = '11111111111111111111111111111111';
/**
* Fetch the SRSLY Address Lookup Table from chain
*
* The ALT contains static addresses used across all rental operations,
* reducing transaction size by ~310 bytes when used with versioned transactions.
*
* @param rpcUrl - Optional RPC endpoint URL. If not provided, uses RPC from global config
* @returns ALT data with addresses, or null if ALT not configured
* @throws Error if fetch fails
*
* @example
* ```typescript
* // Fetch ALT using global config RPC
* const alt = await fetchLookupTable();
* if (alt) {
* console.log('ALT address:', alt.address);
* console.log('Contains', alt.addresses.length, 'addresses');
* }
* ```
*/
async function fetchLookupTable(rpcUrl) {
try {
// Fetch config to get ALT address
const config = await (0, config_1.fetchConfig)(rpcUrl);
const altAddress = config.data.lookupTable;
// Return null if ALT not configured (default pubkey)
if (altAddress === SYSTEM_PROGRAM_ID) {
return null;
}
// Fetch ALT account data
const resolvedRpcUrl = rpcUrl || (0, config_2.getRpcUrl)();
const rpc = (0, rpc_1.createRpc)(resolvedRpcUrl);
const accountInfo = await rpc.getAccountInfo(altAddress, { encoding: 'base64' }).send();
if (!accountInfo.value) {
return null;
}
// Decode ALT data
// ALT format: https://docs.solanalabs.com/implemented-proposals/address-lookup-table
// Header: 56 bytes (discriminator, deactivation_slot, last_extended_slot, etc.)
// Addresses: remaining bytes, 32 bytes each
const data = base64ToUint8Array(accountInfo.value.data[0]);
// Skip 56-byte header to get to addresses
const HEADER_SIZE = 56;
const ADDRESS_SIZE = 32;
const addresses = [];
for (let i = HEADER_SIZE; i < data.length; i += ADDRESS_SIZE) {
const addressBytes = data.subarray(i, i + ADDRESS_SIZE);
// Convert to base58 address string
addresses.push(bs58Encode(addressBytes));
}
return {
address: altAddress,
addresses,
isActive: addresses.length > 0,
};
}
catch (error) {
throw new Error(`Failed to fetch lookup table: ${error.message}`);
}
}
/**
* Get the ALT address from config without fetching full ALT data
*
* @param rpcUrl - Optional RPC endpoint URL
* @returns ALT address, or null if not configured
*/
async function getLookupTableAddress(rpcUrl) {
const config = await (0, config_1.fetchConfig)(rpcUrl);
const altAddress = config.data.lookupTable;
if (altAddress === SYSTEM_PROGRAM_ID) {
return null;
}
return altAddress;
}
/**
* Browser-compatible base64 to Uint8Array decoder
* Uses atob which is available in browsers and Node.js 16+
*/
function base64ToUint8Array(base64) {
const binaryString = atob(base64);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes;
}
/**
* Simple base58 encoder for address bytes
* Using a minimal implementation to avoid additional dependencies
*/
function bs58Encode(bytes) {
const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
const BASE = 58;
if (bytes.length === 0)
return '';
// Count leading zeros
let zeros = 0;
while (zeros < bytes.length && bytes[zeros] === 0) {
zeros++;
}
// Convert to base58
const input = Array.from(bytes);
const encoded = [];
for (const byte of input) {
let carry = byte;
for (let i = 0; i < encoded.length; i++) {
carry += encoded[i] << 8;
encoded[i] = carry % BASE;
carry = Math.floor(carry / BASE);
}
while (carry > 0) {
encoded.push(carry % BASE);
carry = Math.floor(carry / BASE);
}
}
// Add leading zeros
let result = ALPHABET[0].repeat(zeros);
// Convert to string (encoded is in reverse order)
for (let i = encoded.length - 1; i >= 0; i--) {
result += ALPHABET[encoded[i]];
}
return result;
}
//# sourceMappingURL=lookupTable.js.map