|
@@ -11,6 +11,8 @@ import {
|
|
|
SendOptions,
|
|
|
VersionedTransaction,
|
|
|
RpcResponseAndContext,
|
|
|
+ BlockhashWithExpiryBlockHeight,
|
|
|
+ SignatureResult,
|
|
|
Keypair,
|
|
|
} from "@solana/web3.js";
|
|
|
import { bs58 } from "./utils/bytes/index.js";
|
|
@@ -33,7 +35,7 @@ export default interface Provider {
|
|
|
sendAndConfirm?(
|
|
|
tx: Transaction | VersionedTransaction,
|
|
|
signers?: Signer[],
|
|
|
- opts?: ConfirmOptions
|
|
|
+ opts?: ConfirmOptionsWithBlockhash
|
|
|
): Promise<TransactionSignature>;
|
|
|
sendAll?<T extends Transaction | VersionedTransaction>(
|
|
|
txWithSigners: {
|
|
@@ -136,7 +138,7 @@ export class AnchorProvider implements Provider {
|
|
|
async sendAndConfirm(
|
|
|
tx: Transaction | VersionedTransaction,
|
|
|
signers?: Signer[],
|
|
|
- opts?: ConfirmOptions
|
|
|
+ opts?: ConfirmOptionsWithBlockhash
|
|
|
): Promise<TransactionSignature> {
|
|
|
if (opts === undefined) {
|
|
|
opts = this.opts;
|
|
@@ -350,6 +352,10 @@ export type SendTxRequest = {
|
|
|
signers: Array<Signer | undefined>;
|
|
|
};
|
|
|
|
|
|
+export type ConfirmOptionsWithBlockhash = ConfirmOptions & {
|
|
|
+ blockhash?: BlockhashWithExpiryBlockHeight;
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* Wallet interface for objects that can be used to sign provider transactions.
|
|
|
* VersionedTransactions sign everything at once
|
|
@@ -371,32 +377,69 @@ export interface Wallet {
|
|
|
async function sendAndConfirmRawTransaction(
|
|
|
connection: Connection,
|
|
|
rawTransaction: Buffer | Uint8Array,
|
|
|
- options?: ConfirmOptions
|
|
|
+ options?: ConfirmOptionsWithBlockhash
|
|
|
): Promise<TransactionSignature> {
|
|
|
- const sendOptions = options && {
|
|
|
- skipPreflight: options.skipPreflight,
|
|
|
- preflightCommitment: options.preflightCommitment || options.commitment,
|
|
|
- };
|
|
|
-
|
|
|
- const signature = await connection.sendRawTransaction(
|
|
|
- rawTransaction,
|
|
|
- sendOptions
|
|
|
- );
|
|
|
-
|
|
|
- const status = (
|
|
|
- await connection.confirmTransaction(
|
|
|
- signature,
|
|
|
- options && options.commitment
|
|
|
- )
|
|
|
- ).value;
|
|
|
-
|
|
|
- if (status.err) {
|
|
|
- throw new ConfirmError(
|
|
|
- `Raw transaction ${signature} failed (${JSON.stringify(status)})`
|
|
|
- );
|
|
|
+ const sendOptions: SendOptions = options
|
|
|
+ ? {
|
|
|
+ skipPreflight: options.skipPreflight,
|
|
|
+ preflightCommitment: options.preflightCommitment || options.commitment,
|
|
|
+ maxRetries: options.maxRetries,
|
|
|
+ minContextSlot: options.minContextSlot,
|
|
|
+ }
|
|
|
+ : {};
|
|
|
+
|
|
|
+ let status: SignatureResult;
|
|
|
+
|
|
|
+ const startTime = Date.now();
|
|
|
+ while (Date.now() - startTime < 60_000) {
|
|
|
+ try {
|
|
|
+ const signature = await connection.sendRawTransaction(
|
|
|
+ rawTransaction,
|
|
|
+ sendOptions
|
|
|
+ );
|
|
|
+
|
|
|
+ if (options?.blockhash) {
|
|
|
+ if (sendOptions.maxRetries === 0) {
|
|
|
+ const abortSignal = AbortSignal.timeout(15_000);
|
|
|
+ status = (
|
|
|
+ await connection.confirmTransaction(
|
|
|
+ { abortSignal, signature, ...options.blockhash },
|
|
|
+ options && options.commitment
|
|
|
+ )
|
|
|
+ ).value;
|
|
|
+ } else {
|
|
|
+ status = (
|
|
|
+ await connection.confirmTransaction(
|
|
|
+ { signature, ...options.blockhash },
|
|
|
+ options && options.commitment
|
|
|
+ )
|
|
|
+ ).value;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ status = (
|
|
|
+ await connection.confirmTransaction(
|
|
|
+ signature,
|
|
|
+ options && options.commitment
|
|
|
+ )
|
|
|
+ ).value;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (status.err) {
|
|
|
+ throw new ConfirmError(
|
|
|
+ `Raw transaction ${signature} failed (${JSON.stringify(status)})`
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ return signature;
|
|
|
+ } catch (err) {
|
|
|
+ if (err.name === "TimeoutError") {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ throw err;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return signature;
|
|
|
+ throw Error("Transaction failed to confirm in 60s");
|
|
|
}
|
|
|
|
|
|
class ConfirmError extends Error {
|