Skip to content

Instantly share code, notes, and snippets.

@codebender828
Last active April 24, 2024 16:55
Show Gist options
  • Save codebender828/61c3b75a3f1a776092d9910ec0229dbd to your computer and use it in GitHub Desktop.
Save codebender828/61c3b75a3f1a776092d9910ec0229dbd to your computer and use it in GitHub Desktop.
Airdrop Script
async function executeAirdropTransaction() {
const connectionManager = await createConnection("mainnet-beta");
// Generate Transactions
// const instructions: TransactionInstruction[] = [];
// const transactions: Transaction[] = [];
const airdropTransactionEntries = Object.values(airdropTransactionsLogs);
const lastSuccessfulIndex = airdropTransactionEntries.findLastIndex(
(value) => !value.signature
);
for (let i = lastSuccessfulIndex; i < airdropTransactionEntries.length; i++) {
const transactionEntry = airdropTransactionEntries[i];
// Retrieve transaction
const txAsBuffer = Buffer.from(
transactionEntry.serializedTransaction,
"base64"
);
const transaction = VersionedTransaction.deserialize(txAsBuffer);
const prioritizationFees = await getTransferPrioritizationFees([]);
const ComputeUnitPriceInstruction =
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: prioritizationFees.result.priorityFeeLevels.medium,
});
const ComputeUnitLimitInstruction =
ComputeBudgetProgram.setComputeUnitLimit({ units: 400_000 });
const PRIORITIZATION_INSTRUCTIONS = [
ComputeUnitLimitInstruction,
ComputeUnitPriceInstruction,
];
const { blockhash } = await retriableGetRecentBlockHash(connectionManager);
transaction.message.recentBlockhash = blockhash;
const message = TransactionMessage.decompile(transaction.message);
message.instructions = [
...PRIORITIZATION_INSTRUCTIONS,
...message.instructions,
];
message.recentBlockhash = blockhash;
transaction.message = message.compileToV0Message();
transaction.sign([sauceAirdropAuthority]);
let signature: string = "";
const connection = connectionManager.connSync({ changeConn: true });
let blockheight = await connection.getBlockHeight();
const txid = await connection.sendRawTransaction(transaction.serialize(), {
maxRetries: 50,
});
signature = txid;
blockheight = await connection.getBlockHeight();
consola.info(`tx sent transaction meta at blockheight: ${blockheight}`, {
signature,
});
const latestBlockHash = await connection.getLatestBlockhash();
const result = await connection.confirmTransaction(
{
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature,
},
"confirmed"
);
if (!result.value.err) {
const writeableTransactionLog: TransactionLog = {};
writeableTransactionLog[transactionEntry.key] = {
...transactionEntry,
signature,
status: "confirmed",
};
const mergedLog = mergeWith(
airdropTransactions,
writeableTransactionLog
) as TransactionLog;
const txFileName = `airdrop_tx_logs_${CHUNK_INDEX}.json`;
writeFileSync(
resolve(PATH_TO_TX_DIRECTORY, txFileName),
JSON.stringify(mergedLog, null, 2)
);
const progressPercentage = Intl.NumberFormat("en-US", {
style: "percent",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(i / airdropTransactionEntries.length);
consola.info(
`${progressPercentage}: Completed ${i + 1} of ${
airdropTransactionEntries.length
} transactions: ${signature}`
);
} else {
console.info(result);
}
}
}
{
"NO5OLOnPJ0QRtcOPMAR7J": {
"serializedTransaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAHDOi11/KX0/UVwyAmROlXL4BGSoO47oOHX1mQfCjZQaL6gNDAekMP0xLQhQIaOAxQ+p9QPlpJtkentaZR5RXpW55RNvOv/p6ncl7YEXbxK1912yuEvmqw3MBMVPx51Qf752TS3GeO3WcJ6YGNCvYHx3C2Wd5Ql0bv9UAcg6OhXIleWaXW1WYucmTqDGhUhBwHB2fnwR/RwYpq0SKPt8rh9UOMlyWPTiSJ8bs9ECkUjg2DC1oTmdr/EIQEjnvY2+n4WXMB+zuioFTkz3d8tgeTLt/RNoizIWM0GG7Kg1OHdc8dLNyEGqAFP6Who53i1Z7wf+zT4SILbsY7ejyhZi+K3GoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpEFQrjD8G6/Pa0On0ICny/4tRXDfGGtlwX0pJtn1/S9Z2lfTQzCUdpG37INLVIv4x3u17nFw05Z52az22h7r9d4BNpQSCDMs9SEqGUDrOnPj3yPC/YpbINoA0XPf2Z7z7BgUGAAEGBwgJAAkEAgcBAAoMwA1KZJIAAAAJBQYAAwoHCAkACQQCBwMACgyg44gZGAMAAAkFBgAECwcICQAJBAIHBAAKDOCFDVAFAAAACQA=",
"key": "NO5OLOnPJ0QRtcOPMAR7J"
},
"An8WAfeHS65MxkKtxKQdh": {
"serializedTransaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQACBei11/KX0/UVwyAmROlXL4BGSoO47oOHX1mQfCjZQaL6UTbzr/6ep3Je2BF28StfddsrhL5qsNzATFT8edUH++eEgOIIl019puDieM6oWgUD7u3pjb1LyWnMX2UUElv4ygbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpLNyEGqAFP6Who53i1Z7wf+zT4SILbsY7ejyhZi+K3GqATaUEggzLPUhKhlA6zpz498jwv2KWyDaANFz39me8+wEDBAEEAgAKDACWgz2nAQAACQA=",
"key": "An8WAfeHS65MxkKtxKQdh"
}
}
@codebender828
Copy link
Author

Here if transaction is confirmed, I log and write to file. So in case of failure the script picks up from where it left off.
https://gist.github.com/codebender828/61c3b75a3f1a776092d9910ec0229dbd#file-execute_airdrop-ts-L77-L94


Here, I compute priority fees
https://gist.github.com/codebender828/61c3b75a3f1a776092d9910ec0229dbd#file-execute_airdrop-ts-L23-L35

Get priority fees estimate

const url = "https://gretta-szjwp2-fast-mainnet.helius-rpc.com";

export interface PrioritizationFeesResponse {
  jsonrpc: string;
  result: Result;
  id: number;
}

export interface Result {
  priorityFeeLevels: PriorityFeeLevels;
}

export interface PriorityFeeLevels {
  min: number;
  low: number;
  medium: number;
  high: number;
  veryHigh: number;
  unsafeMax: number;
}

export const getRecentPrioritizationFees = async (
  accountKeys: PublicKey[] = [TOKEN_PROGRAM_ID]
) => {
  const response = await fetch(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: 1,
      method: "getPriorityFeeEstimate",
      params: [
        {
          accountKeys: accountKeys.map((key) => key.toBase58()),
          options: {
            includeAllPriorityFeeLevels: true,
          },
        },
      ],
    }),
  });
  const data = (await response.json()) as PrioritizationFeesResponse;
  return data;
};

@codebender828
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment