Ver código fonte

ts: Add optional `options.blockhash` to `Provider.sendAndConfirm` (#3070)

dev4all.sol 1 ano atrás
pai
commit
a245dce292

+ 1 - 0
CHANGELOG.md

@@ -12,6 +12,7 @@ The minor version will be incremented upon a breaking change and the patch versi
 
 ### Features
 
+- ts: Add optional `options.blockhash` to `Provider.sendAndConfirm` ([#3070](https://github.com/coral-xyz/anchor/pull/3070)).
 - ts: Add optional `commitment` parameter to `Program.addEventListener` ([#3052](https://github.com/coral-xyz/anchor/pull/3052)).
 - cli, idl: Pass `cargo` args to IDL generation when building program or IDL ([#3059](https://github.com/coral-xyz/anchor/pull/3059)).
 - cli: Add checks for incorrect usage of `idl-build` feature ([#3061](https://github.com/coral-xyz/anchor/pull/3061)).

+ 1 - 1
ts/packages/anchor/package.json

@@ -36,7 +36,7 @@
     "@coral-xyz/anchor-errors": "^0.30.1",
     "@coral-xyz/borsh": "^0.30.1",
     "@noble/hashes": "^1.3.1",
-    "@solana/web3.js": "^1.68.0",
+    "@solana/web3.js": "^1.69.0",
     "bn.js": "^5.1.2",
     "bs58": "^4.0.1",
     "buffer-layout": "^1.2.2",

+ 68 - 25
ts/packages/anchor/src/provider.ts

@@ -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 {

+ 1 - 1
ts/packages/borsh/package.json

@@ -24,7 +24,7 @@
     "buffer-layout": "^1.2.0"
   },
   "peerDependencies": {
-    "@solana/web3.js": "^1.68.0"
+    "@solana/web3.js": "^1.69.0"
   },
   "files": [
     "dist"

+ 4 - 4
ts/yarn.lock

@@ -985,10 +985,10 @@
   dependencies:
     buffer "~6.0.3"
 
-"@solana/web3.js@^1.32.0", "@solana/web3.js@^1.68.0":
-  version "1.68.0"
-  resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.68.0.tgz#ded078d6e72f9f4b46e0f69925d4fe5c6cdcef54"
-  integrity sha512-i41x4ArQrjdy/iQf75vKwZa+Mx1hOVquamHHe+5lNbObF4CT57oHOTvG9m9DTypuip3O9ucLoryywd6LfP2eEw==
+"@solana/web3.js@^1.32.0", "@solana/web3.js@^1.69.0":
+  version "1.69.0"
+  resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.69.0.tgz#1756b1a26087172291c0b5163d3b44d24eef8aa7"
+  integrity sha512-iU2Q0IG25RITsxBkY1Vkk74LffRokViEcSblz4CGxyt+/V7xSkC2DNM0n0rB3aY/9+FvMiz4l5wHnD9UC4Ac/w==
   dependencies:
     "@babel/runtime" "^7.12.5"
     "@noble/ed25519" "^1.7.0"