Skip to content

Instantly share code, notes, and snippets.

@a26nine
Last active October 16, 2022 11:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a26nine/874a0046cb3c75362213e1c2ebf9faad to your computer and use it in GitHub Desktop.
Save a26nine/874a0046cb3c75362213e1c2ebf9faad to your computer and use it in GitHub Desktop.
Address Lookup Tables and Versioned Transactions on Solana (from blog.a269nine.dev)
// Import required modules
const solana = require('@solana/web3.js');
const bs58 = require('bs58');
// Set required variables
const PRIVATE_KEY = [YOUR_PRIVATE_KEY_FROM_PHANTOM_WALLET];
const ENDPOINT = [YOUR_QUICKNODE_ENDPOINT_URL];
// List of account addresses for lookup table
let tableEntries = [
// Add account addresses
];
// Function to pause app for sometime
async function pause() {
await new Promise((resolve) => setTimeout(resolve, 5000)); // Value in ms
}
// Create connection to endpoint
async function createConn() {
return new solana.Connection(ENDPOINT, 'confirmed');
}
// Fetch latest blockhash
const getLatestBlockhash = (connection) => {
return connection
.getLatestBlockhash('finalized')
.then((res) => res.blockhash);
};
// Create lookup table
async function createLookupTable(connection, payer) {
const [lookupTableInst, lookupTableAddress] =
solana.AddressLookupTableProgram.createLookupTable({
authority: payer.publicKey,
payer: payer.publicKey,
recentSlot: await connection.getSlot(),
});
return [lookupTableInst, lookupTableAddress];
}
// Extend lookup table
async function extendLookupTable(payer, lookupTableAddress, addressList) {
const extendInst = solana.AddressLookupTableProgram.extendLookupTable({
addresses: addressList,
authority: payer.publicKey,
lookupTable: lookupTableAddress,
payer: payer.publicKey,
});
return extendInst;
}
// Send tx (all types)
async function sendTx(connection, payer, inst, lookupTable, compareTxSize) {
let message;
if (lookupTable) {
message = new solana.TransactionMessage({
instructions: inst,
payerKey: payer.publicKey,
recentBlockhash: await getLatestBlockhash(connection),
}).compileToV0Message([lookupTable]);
} else {
message = new solana.TransactionMessage({
instructions: inst,
payerKey: payer.publicKey,
recentBlockhash: await getLatestBlockhash(connection),
}).compileToV0Message();
}
const tx = new solana.VersionedTransaction(message);
tx.sign([payer]);
if (compareTxSize) {
console.log(
lookupTable
? '🟒 [With Address Lookup Table]'
: 'πŸ”΄ [Without Address Lookup Table]',
'Tx Size:',
tx.serialize().length,
'bytes'
);
}
const txId = await connection.sendTransaction(tx);
return txId;
}
// Main app
async function app() {
console.log(
'πŸ‘€ Solana - Address Lookup Tables / Versioned Transactions πŸ‘€'
);
// Decode the private key and create a new Keypair
const privKey = bs58.decode(PRIVATE_KEY);
const myWallet = solana.Keypair.fromSecretKey(privKey);
// Esablish connection to endpoint
const conn = await createConn();
console.log('βœ… Endpoint connected!');
// Create lookup table
const [lookupTableInst, lookupTableAddress] = await createLookupTable(
conn,
myWallet
);
console.log(
`πŸ“ Address Lookup Table Details --- ${lookupTableAddress} | https://explorer.solana.com/address/${lookupTableAddress.toBase58()}?cluster=devnet`
);
await pause();
const createTableTxId = await sendTx(conn, myWallet, [lookupTableInst]);
console.log(
`βœ… Address Lookup Table Created: https://explorer.solana.com/tx/${createTableTxId}?cluster=devnet`
);
await pause();
// Populate account address list to add to lookup table
let addressList = new Array();
addressList.push(myWallet.publicKey);
tableEntries.forEach((entry) => {
addressList.push(new solana.PublicKey(entry));
});
// Extend lookup table
const extendInst = await extendLookupTable(
myWallet,
lookupTableAddress,
addressList
);
const ExtTableTxId = await sendTx(conn, myWallet, [extendInst]);
console.log(
`βœ… Address Lookup Table Extended: https://explorer.solana.com/tx/${ExtTableTxId}?cluster=devnet`
);
await pause();
// Fetch lookup table data
const lookupTableAccount = await conn
.getAddressLookupTable(lookupTableAddress)
.then((res) => res.value);
console.log('🧾 Verifying Addresses in the Lookup Table...');
for (let i = 0; i < lookupTableAccount.state.addresses.length; i++) {
const address = lookupTableAccount.state.addresses[i];
console.log('Address', i + 1, address.toBase58());
}
// Create instructions array for txs
const txInst = new Array();
for (let i = 0; i < lookupTableAccount.state.addresses.length; i++) {
const address = lookupTableAccount.state.addresses[i];
txInst.push(
solana.SystemProgram.transfer({
fromPubkey: myWallet.publicKey,
toPubkey: address,
lamports: 0.0001 * solana.LAMPORTS_PER_SOL, // 0.0001 SOL
})
);
}
// Tx with lookup table
const sendNewTx1 = await sendTx(
conn,
myWallet,
txInst,
lookupTableAccount,
true
);
// Tx without lookup table
const sendNewTx2 = await sendTx(conn, myWallet, txInst, null, true);
console.log(
`πŸš€ Versioned Transaction with the Address Lookup Table: https://explorer.solana.com/tx/${sendNewTx1}?cluster=devnet`
);
}
app();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment