Skip to content

Instantly share code, notes, and snippets.

@mgild
Created April 1, 2024 04:58
Show Gist options
  • Save mgild/05b00962f5a475a553a58ccef03b1ad2 to your computer and use it in GitHub Desktop.
Save mgild/05b00962f5a475a553a58ccef03b1ad2 to your computer and use it in GitHub Desktop.
import {
TransactionInstruction,
Connection,
PublicKey,
Keypair,
Transaction,
SystemProgram,
LAMPORTS_PER_SOL,
} from "@solana/web3.js";
import { Program } from "@coral-xyz/anchor";
import * as anchor from "@coral-xyz/anchor";
import {
VersionedTransaction,
TransactionMessage,
AddressLookupTableAccount,
ComputeBudgetProgram,
} from "@solana/web3.js";
import bs58 from "bs58";
class TransactionBuilder {
private program: Program;
private heliusUrl?: string;
private blockhash: string = "";
private computeUnitLimit: number = 1_400_000;
private computeUnitLimitMultiple: number = 1;
private computeUnitPrice: number = 0;
private setAutoComputeUnitMultiple?: number = undefined;
private ixs: Array<TransactionInstruction>;
private lookupTables: Array<AddressLookupTableAccount>;
constructor(
program: Program,
ixs: Array<TransactionInstruction>,
heliusUrl?: string,
lookupTables?: Array<AddressLookupTableAccount>
) {
this.program = program;
this.ixs = ixs;
this.heliusUrl = heliusUrl;
this.lookupTables = lookupTables ?? [];
console.log(`heliusUrl: ${this.heliusUrl}`);
}
static create(
program: Program,
ixs: Array<TransactionInstruction>,
heliusUrl?: string,
lookupTables?: Array<AddressLookupTableAccount>
): TransactionBuilder {
return new TransactionBuilder(program, ixs, heliusUrl, lookupTables);
}
setComputeLimitMultiple(multiple: number): TransactionBuilder {
this.computeUnitLimitMultiple = multiple;
return this;
}
setComputeUnitLimit(limit: number): TransactionBuilder {
this.computeUnitLimit = limit;
return this;
}
setComputeUnitPrice(price: number): TransactionBuilder {
this.computeUnitPrice = price;
return this;
}
setBlockhash(blockhash: string): TransactionBuilder {
this.blockhash = blockhash;
return this;
}
async setAutoComputeUnitLimit(): Promise<TransactionBuilder> {
const ixs = this.ixs;
const lookupTables = this.lookupTables;
const program = this.program;
const computeUnitLimitMultiple = this.computeUnitLimitMultiple;
const computeUnitPrice = this.computeUnitPrice;
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({
microLamports: computeUnitPrice,
});
const simulationComputeLimitIx = ComputeBudgetProgram.setComputeUnitLimit({
units: 1_400_000,
});
let recentBlockhash = this.blockhash;
if (recentBlockhash === "") {
recentBlockhash = (await program.provider.connection.getLatestBlockhash())
.blockhash;
}
const simulateMessageV0 = new TransactionMessage({
recentBlockhash,
instructions: [priorityFeeIx, simulationComputeLimitIx, ...ixs],
payerKey: program.provider.publicKey!,
}).compileToV0Message(lookupTables);
const simulationResult =
await program.provider.connection.simulateTransaction(
new VersionedTransaction(simulateMessageV0),
{
commitment: "processed",
sigVerify: false,
}
);
const simulationUnitsConsumed = simulationResult.value.unitsConsumed!;
console.log(`simulationUnitsConsumed: ${simulationUnitsConsumed}`);
this.computeUnitLimit = Math.floor(
simulationUnitsConsumed * computeUnitLimitMultiple
);
console.log(`computeUnitLimit: ${this.computeUnitLimit}`);
return this;
}
async setAutoComputeUnitPrice(
level: "min" | "low" | "medium" | "high" | "veryHigh" | "unsafeMax"
): Promise<TransactionBuilder> {
if ((this.heliusUrl ?? "") === "") {
throw new Error("Helius URL is not set");
}
if (this.blockhash === "") {
this.blockhash = (
await this.program.provider.connection.getLatestBlockhash()
).blockhash;
}
console.log(`ixs.length: ${this.ixs.length}`);
const simulateMessageV0 = new TransactionMessage({
recentBlockhash: this.blockhash,
instructions: this.ixs,
payerKey: this.program.provider.publicKey!,
}).compileToV0Message(this.lookupTables);
const transaction = new VersionedTransaction(simulateMessageV0);
const response = await fetch(this.heliusUrl!, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: `${Math.floor(Math.random() * 100_000_000)}`,
method: "getPriorityFeeEstimate",
params: [
{
transaction: bs58.encode(transaction.serialize()),
options: { includeAllPriorityFeeLevels: true },
},
],
}),
});
const data = await response.json();
this.computeUnitPrice = Math.floor(data.result.priorityFeeLevels[level]);
console.log(`computeUnitPrice: ${this.computeUnitPrice}`);
return this;
}
build(): VersionedTransaction {
let recentBlockhash = this.blockhash;
const microLamports = this.computeUnitPrice;
const units = this.computeUnitLimit;
if (recentBlockhash === "") {
throw new Error("Blockhash is not set");
}
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({
microLamports,
});
const computeLimitIx = ComputeBudgetProgram.setComputeUnitLimit({ units });
const messageV0 = new TransactionMessage({
recentBlockhash,
instructions: [priorityFeeIx, computeLimitIx, ...this.ixs],
payerKey: this.program.provider.publicKey!,
}).compileToV0Message(this.lookupTables);
console.log(`computeUnitPrice: ${this.computeUnitPrice}`);
console.log(`computeUnitLimit: ${this.computeUnitLimit}`);
return new VersionedTransaction(messageV0);
}
}
(async () => {
let PID = new PublicKey("SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f");
let url =
"https://rpc.ironforge.network/mainnet?apiKey=01HRZ9G6Z2A19FY8PR4RF4J4PW";
let connection = new Connection(url, {
commitment: "confirmed",
});
const programId = new anchor.web3.PublicKey(PID);
const wallet = new anchor.Wallet(Keypair.generate());
const provider = new anchor.AnchorProvider(connection, wallet, {});
const idl = await anchor.Program.fetchIdl(programId, provider);
const program = new anchor.Program(idl!, programId, provider);
const heliusUrl =
"https://mainnet.helius-rpc.com/?api-key=adc292a6-6148-4ca7-b68e-fa55ef679e09";
const recentBlockhash = (
await program.provider.connection.getLatestBlockhash()
).blockhash;
const ix = await createInstruction(wallet.publicKey, wallet.publicKey);
const tx = await TransactionBuilder.create(program, [ix], heliusUrl)
.setBlockhash(recentBlockhash)
.setComputeLimitMultiple(1.2)
.setAutoComputeUnitPrice("low")
.then((builder: TransactionBuilder) => builder.setAutoComputeUnitLimit())
.then((builder: TransactionBuilder) => builder.build());
console.log(tx);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment