-
-
Save mgild/05b00962f5a475a553a58ccef03b1ad2 to your computer and use it in GitHub Desktop.
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 { | |
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