Last active
October 16, 2022 11:36
-
-
Save a26nine/874a0046cb3c75362213e1c2ebf9faad to your computer and use it in GitHub Desktop.
Address Lookup Tables and Versioned Transactions on Solana (from blog.a269nine.dev)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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