Created
December 16, 2024 05:05
-
-
Save metaproph3t/a63c824bcd784ee2ac341a66ae53cda6 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 { WalletContextState } from "@solana/wallet-adapter-react"; | |
import { | |
Transaction, | |
Connection, | |
SignatureStatus, | |
ComputeBudgetProgram, | |
} from "@solana/web3.js"; | |
// Taken from: | |
// https://github.com/rpcpool/solana-prioritization-fees-api/ | |
import { | |
getMedianPrioritizationFeeByPercentile, | |
PriotitizationFeeLevels, | |
} from "./grpf"; | |
import { backOff } from "exponential-backoff"; | |
// A minute of retries, with 2 second intervals | |
const RETRY_INTERVAL_MS = 2000; | |
const MAX_RETRIES = 30; | |
// 10k CUs is 0.03 cents, assuming 150k CUs and $250 SOL | |
const MIN_CU_PRICE = 10_000; | |
// 10M CUs is $0.38, assuming 150k CUs and $250 SOL | |
const MAX_CU_PRICE = 10_000_000; | |
type TxStatusUpdate = | |
| { status: "created" } | |
| { status: "signed" } | |
| { status: "sent"; signature: string } | |
| { status: "confirmed"; result: SignatureStatus }; | |
// Sign and send a transaction with a priority fee. Assumes that the caller has already set the compute unit limit. | |
export async function signAndSendTransaction( | |
connection: Connection, | |
wallet: WalletContextState, | |
txn: Transaction, | |
onStatusUpdate?: (status: TxStatusUpdate) => void, | |
) { | |
if (!wallet.publicKey) { | |
throw new Error("Wallet not connected"); | |
} | |
if (!wallet.signTransaction) { | |
throw new Error("Wallet does not support signing transactions"); | |
} | |
let latestBlockhash; | |
try { | |
latestBlockhash = await backOff( | |
async () => (await connection.getLatestBlockhash("confirmed")).blockhash, | |
); | |
} catch (e) { | |
throw new Error("Unable to get latest blockhash"); | |
} | |
txn.recentBlockhash = latestBlockhash; | |
txn.feePayer = wallet.publicKey; | |
let medianPriorityFee; | |
try { | |
medianPriorityFee = await backOff( | |
async () => | |
await getMedianPrioritizationFeeByPercentile(connection, { | |
percentile: PriotitizationFeeLevels.HIGH, | |
}), | |
); | |
} catch (e) { | |
throw new Error("Unable to get median priority fee"); | |
} | |
const priorityFee = Math.min( | |
Math.max(medianPriorityFee, MIN_CU_PRICE), | |
MAX_CU_PRICE, | |
); | |
txn.add( | |
ComputeBudgetProgram.setComputeUnitPrice({ | |
microLamports: priorityFee, | |
}), | |
); | |
onStatusUpdate?.({ status: "created" }); | |
let signedTx; | |
try { | |
signedTx = await wallet.signTransaction(txn); | |
} catch (e) { | |
throw new Error("Wallet rejected transaction"); | |
} | |
onStatusUpdate?.({ status: "signed" }); | |
let retries = 0; | |
let signature: string | null = null; | |
let status: SignatureStatus | null = null; | |
while (retries < MAX_RETRIES) { | |
await Promise.all([ | |
(async () => { | |
try { | |
const isFirstSend = signature === null; | |
signature = await connection.sendRawTransaction( | |
signedTx.serialize(), | |
{ | |
skipPreflight: true, | |
preflightCommitment: "confirmed", | |
maxRetries: 0, | |
}, | |
); | |
if (isFirstSend) { | |
onStatusUpdate?.({ status: "sent", signature }); | |
} | |
} catch (e) { | |
console.error(e); | |
} | |
})(), | |
(async () => { | |
if (signature) { | |
try { | |
const response = await connection.getSignatureStatus(signature); | |
if (response.value) { | |
status = response.value; | |
} | |
} catch (e) { | |
console.error(e); | |
} | |
} | |
})(), | |
]); | |
retries++; | |
if ( | |
status && | |
((status as SignatureStatus).confirmationStatus === "confirmed" || | |
(status as SignatureStatus).confirmationStatus === "finalized") | |
) { | |
onStatusUpdate?.({ status: "confirmed", result: status }); | |
break; | |
} | |
await new Promise((resolve) => setTimeout(resolve, RETRY_INTERVAL_MS)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment