Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Gauntlet support for custom unit price and limit #425

Merged
merged 2 commits into from Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -74,7 +74,10 @@ export const wrapCommand = (command) => {
if (this.flags.execute) {
await prompt('Continue?')
logger.loading(`Executing action...`)
const txhash = await this.sendTxWithIDL(this.signAndSendRawTx, this.program.idl)(rawTxs)
const txhash = await this.sendTxWithIDL(this.signAndSendRawTx, this.program.idl)(rawTxs, null, {
price: Number(this.flags.computePrice),
units: Number(this.flags.computeUnits),
})
logger.success(`TX succeded at ${txhash}`)

const msigState = await this.fetchMultisigState(this.multisigAddress)
Expand All @@ -90,23 +93,19 @@ export const wrapCommand = (command) => {
}
}

const latestSlot = await this.provider.connection.getSlot()
const recentBlock = await this.provider.connection.getBlock(latestSlot)
if (!recentBlock) {
const { blockhash, lastValidBlockHeight } = await this.provider.connection.getLatestBlockhash()
if (!lastValidBlockHeight) {
throw new Error('Block not found. Could not generate message data')
}
const tx = utils.makeTx(rawTxs, {
recentBlockhash: recentBlock.blockhash,
blockhash,
lastValidBlockHeight,
feePayer: signer,
})

const msgData = tx.serializeMessage().toString('base64')
logger.line()
logger.success(
`Message generated with blockhash ID: ${recentBlock.blockhash.toString()} (${new Date(
recentBlock.blockTime! * 1000,
).toLocaleString()}). MESSAGE DATA:`,
)
logger.success(`Message generated with blockhash ID: ${blockhash.toString()}). MESSAGE DATA:`)
logger.log()
logger.log(msgData)
logger.log()
Expand Down
Expand Up @@ -81,12 +81,23 @@ export default abstract class SolanaCommand extends WriteCommand<TransactionResp
signAndSendRawTx = async (
rawTxs: TransactionInstruction[],
extraSigners?: Keypair[],
overrides: {
units?: number
price?: number
} = {},
): Promise<TransactionSignature> => {
const recentBlockhash = (await this.provider.connection.getRecentBlockhash()).blockhash
const tx = makeTx(rawTxs, {
recentBlockhash,
feePayer: this.wallet.publicKey,
})
const { blockhash, lastValidBlockHeight } = await this.provider.connection.getLatestBlockhash()
if (overrides.units) logger.info(`Sending transaction with custom unit limit: ${overrides.units}`)
if (overrides.price) logger.info(`Sending transaction with custom unit price: ${overrides.price}`)
const tx = makeTx(
rawTxs,
{
blockhash,
lastValidBlockHeight,
feePayer: this.wallet.publicKey,
},
overrides,
)
if (extraSigners) {
tx.sign(...extraSigners)
}
Expand All @@ -113,8 +124,11 @@ export default abstract class SolanaCommand extends WriteCommand<TransactionResp

simulateTx = async (signer: PublicKey, txInstructions: TransactionInstruction[], feePayer?: PublicKey) => {
try {
const { blockhash, lastValidBlockHeight } = await this.provider.connection.getLatestBlockhash()
const tx = makeTx(txInstructions, {
feePayer: feePayer || signer,
blockhash,
lastValidBlockHeight,
})
// simulating through connection allows to skip signing tx (useful when using Ledger device)
const { value: simulationResponse } = await this.provider.connection.simulateTransaction(tx)
Expand Down
18 changes: 15 additions & 3 deletions gauntlet/packages/gauntlet-solana/src/lib/utils.ts
@@ -1,5 +1,17 @@
import { Transaction, TransactionInstruction, TransactionCtorFields } from '@solana/web3.js'
import { Transaction, TransactionInstruction, TransactionBlockhashCtor, ComputeBudgetProgram } from '@solana/web3.js'

export const makeTx = (rawTx: TransactionInstruction[], opts?: TransactionCtorFields): Transaction => {
return rawTx.reduce((tx, instruction) => tx.add(instruction), new Transaction(opts))
export const makeTx = (
rawTx: TransactionInstruction[],
opts?: TransactionBlockhashCtor,
overrides: { price?: number; units?: number } = {},
): Transaction => {
if (overrides.price && overrides.units)
throw new Error('Cannot set limit for units and price in the same transaction')

let computeIx: TransactionInstruction
if (overrides.price) computeIx = ComputeBudgetProgram.setComputeUnitPrice({ microLamports: overrides.price })
if (overrides.units) computeIx = ComputeBudgetProgram.setComputeUnitLimit({ units: overrides.units })
const initialTx = computeIx ? new Transaction(opts).add(computeIx) : new Transaction(opts)

return rawTx.reduce((tx, instruction) => tx.add(instruction), initialTx)
}