|
@@ -9,9 +9,11 @@ import {
|
|
Commitment,
|
|
Commitment,
|
|
SendTransactionError,
|
|
SendTransactionError,
|
|
SendOptions,
|
|
SendOptions,
|
|
|
|
+ VersionedTransaction,
|
|
|
|
+ RpcResponseAndContext,
|
|
} from "@solana/web3.js";
|
|
} from "@solana/web3.js";
|
|
import { bs58 } from "./utils/bytes/index.js";
|
|
import { bs58 } from "./utils/bytes/index.js";
|
|
-import { isBrowser } from "./utils/common.js";
|
|
|
|
|
|
+import { isBrowser, isVersionedTransaction } from "./utils/common.js";
|
|
import {
|
|
import {
|
|
simulateTransaction,
|
|
simulateTransaction,
|
|
SuccessfulTxSimulationResponse,
|
|
SuccessfulTxSimulationResponse,
|
|
@@ -22,21 +24,24 @@ export default interface Provider {
|
|
readonly publicKey?: PublicKey;
|
|
readonly publicKey?: PublicKey;
|
|
|
|
|
|
send?(
|
|
send?(
|
|
- tx: Transaction,
|
|
|
|
|
|
+ tx: Transaction | VersionedTransaction,
|
|
signers?: Signer[],
|
|
signers?: Signer[],
|
|
opts?: SendOptions
|
|
opts?: SendOptions
|
|
): Promise<TransactionSignature>;
|
|
): Promise<TransactionSignature>;
|
|
sendAndConfirm?(
|
|
sendAndConfirm?(
|
|
- tx: Transaction,
|
|
|
|
|
|
+ tx: Transaction | VersionedTransaction,
|
|
signers?: Signer[],
|
|
signers?: Signer[],
|
|
opts?: ConfirmOptions
|
|
opts?: ConfirmOptions
|
|
): Promise<TransactionSignature>;
|
|
): Promise<TransactionSignature>;
|
|
- sendAll?(
|
|
|
|
- txWithSigners: { tx: Transaction; signers?: Signer[] }[],
|
|
|
|
|
|
+ sendAll?<T extends Transaction | VersionedTransaction>(
|
|
|
|
+ txWithSigners: {
|
|
|
|
+ tx: T;
|
|
|
|
+ signers?: Signer[];
|
|
|
|
+ }[],
|
|
opts?: ConfirmOptions
|
|
opts?: ConfirmOptions
|
|
): Promise<Array<TransactionSignature>>;
|
|
): Promise<Array<TransactionSignature>>;
|
|
simulate?(
|
|
simulate?(
|
|
- tx: Transaction,
|
|
|
|
|
|
+ tx: Transaction | VersionedTransaction,
|
|
signers?: Signer[],
|
|
signers?: Signer[],
|
|
commitment?: Commitment,
|
|
commitment?: Commitment,
|
|
includeAccounts?: boolean | PublicKey[]
|
|
includeAccounts?: boolean | PublicKey[]
|
|
@@ -124,7 +129,7 @@ export class AnchorProvider implements Provider {
|
|
* @param opts Transaction confirmation options.
|
|
* @param opts Transaction confirmation options.
|
|
*/
|
|
*/
|
|
async sendAndConfirm(
|
|
async sendAndConfirm(
|
|
- tx: Transaction,
|
|
|
|
|
|
+ tx: Transaction | VersionedTransaction,
|
|
signers?: Signer[],
|
|
signers?: Signer[],
|
|
opts?: ConfirmOptions
|
|
opts?: ConfirmOptions
|
|
): Promise<TransactionSignature> {
|
|
): Promise<TransactionSignature> {
|
|
@@ -132,17 +137,23 @@ export class AnchorProvider implements Provider {
|
|
opts = this.opts;
|
|
opts = this.opts;
|
|
}
|
|
}
|
|
|
|
|
|
- tx.feePayer = tx.feePayer || this.wallet.publicKey;
|
|
|
|
-
|
|
|
|
- tx.recentBlockhash = (
|
|
|
|
- await this.connection.getLatestBlockhash(opts.preflightCommitment)
|
|
|
|
- ).blockhash;
|
|
|
|
-
|
|
|
|
|
|
+ if (isVersionedTransaction(tx)) {
|
|
|
|
+ if (signers) {
|
|
|
|
+ tx.sign(signers);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ tx.feePayer = tx.feePayer ?? this.wallet.publicKey;
|
|
|
|
+ tx.recentBlockhash = (
|
|
|
|
+ await this.connection.getLatestBlockhash(opts.preflightCommitment)
|
|
|
|
+ ).blockhash;
|
|
|
|
+
|
|
|
|
+ if (signers) {
|
|
|
|
+ for (const signer of signers) {
|
|
|
|
+ tx.partialSign(signer);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
tx = await this.wallet.signTransaction(tx);
|
|
tx = await this.wallet.signTransaction(tx);
|
|
- (signers ?? []).forEach((kp) => {
|
|
|
|
- tx.partialSign(kp);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
const rawTx = tx.serialize();
|
|
const rawTx = tx.serialize();
|
|
|
|
|
|
try {
|
|
try {
|
|
@@ -155,10 +166,14 @@ export class AnchorProvider implements Provider {
|
|
// (the json RPC does not support any shorter than "confirmed" for 'getTransaction')
|
|
// (the json RPC does not support any shorter than "confirmed" for 'getTransaction')
|
|
// because that will see the tx sent with `sendAndConfirmRawTransaction` no matter which
|
|
// because that will see the tx sent with `sendAndConfirmRawTransaction` no matter which
|
|
// commitment `sendAndConfirmRawTransaction` used
|
|
// commitment `sendAndConfirmRawTransaction` used
|
|
- const failedTx = await this.connection.getTransaction(
|
|
|
|
- bs58.encode(tx.signature!),
|
|
|
|
- { commitment: "confirmed" }
|
|
|
|
|
|
+ const txSig = bs58.encode(
|
|
|
|
+ isVersionedTransaction(tx)
|
|
|
|
+ ? tx.signatures?.[0] || new Uint8Array()
|
|
|
|
+ : tx.signature ?? new Uint8Array()
|
|
);
|
|
);
|
|
|
|
+ const failedTx = await this.connection.getTransaction(txSig, {
|
|
|
|
+ commitment: "confirmed",
|
|
|
|
+ });
|
|
if (!failedTx) {
|
|
if (!failedTx) {
|
|
throw err;
|
|
throw err;
|
|
} else {
|
|
} else {
|
|
@@ -173,34 +188,44 @@ export class AnchorProvider implements Provider {
|
|
|
|
|
|
/**
|
|
/**
|
|
* Similar to `send`, but for an array of transactions and signers.
|
|
* Similar to `send`, but for an array of transactions and signers.
|
|
|
|
+ * All transactions need to be of the same type, it doesn't support a mix of `VersionedTransaction`s and `Transaction`s.
|
|
*
|
|
*
|
|
* @param txWithSigners Array of transactions and signers.
|
|
* @param txWithSigners Array of transactions and signers.
|
|
* @param opts Transaction confirmation options.
|
|
* @param opts Transaction confirmation options.
|
|
*/
|
|
*/
|
|
- async sendAll(
|
|
|
|
- txWithSigners: { tx: Transaction; signers?: Signer[] }[],
|
|
|
|
|
|
+ async sendAll<T extends Transaction | VersionedTransaction>(
|
|
|
|
+ txWithSigners: {
|
|
|
|
+ tx: T;
|
|
|
|
+ signers?: Signer[];
|
|
|
|
+ }[],
|
|
opts?: ConfirmOptions
|
|
opts?: ConfirmOptions
|
|
): Promise<Array<TransactionSignature>> {
|
|
): Promise<Array<TransactionSignature>> {
|
|
if (opts === undefined) {
|
|
if (opts === undefined) {
|
|
opts = this.opts;
|
|
opts = this.opts;
|
|
}
|
|
}
|
|
- const blockhash = await this.connection.getLatestBlockhash(
|
|
|
|
- opts.preflightCommitment
|
|
|
|
- );
|
|
|
|
|
|
+ const recentBlockhash = (
|
|
|
|
+ await this.connection.getLatestBlockhash(opts.preflightCommitment)
|
|
|
|
+ ).blockhash;
|
|
|
|
|
|
let txs = txWithSigners.map((r) => {
|
|
let txs = txWithSigners.map((r) => {
|
|
- let tx = r.tx;
|
|
|
|
- let signers = r.signers ?? [];
|
|
|
|
-
|
|
|
|
- tx.feePayer = tx.feePayer || this.wallet.publicKey;
|
|
|
|
-
|
|
|
|
- tx.recentBlockhash = blockhash.blockhash;
|
|
|
|
|
|
+ if (isVersionedTransaction(r.tx)) {
|
|
|
|
+ let tx: VersionedTransaction = r.tx;
|
|
|
|
+ if (r.signers) {
|
|
|
|
+ tx.sign(r.signers);
|
|
|
|
+ }
|
|
|
|
+ return tx;
|
|
|
|
+ } else {
|
|
|
|
+ let tx: Transaction = r.tx;
|
|
|
|
+ let signers = r.signers ?? [];
|
|
|
|
|
|
- signers.forEach((kp) => {
|
|
|
|
- tx.partialSign(kp);
|
|
|
|
- });
|
|
|
|
|
|
+ tx.feePayer = tx.feePayer ?? this.wallet.publicKey;
|
|
|
|
+ tx.recentBlockhash = recentBlockhash;
|
|
|
|
|
|
- return tx;
|
|
|
|
|
|
+ signers.forEach((kp) => {
|
|
|
|
+ tx.partialSign(kp);
|
|
|
|
+ });
|
|
|
|
+ return tx;
|
|
|
|
+ }
|
|
});
|
|
});
|
|
|
|
|
|
const signedTxs = await this.wallet.signAllTransactions(txs);
|
|
const signedTxs = await this.wallet.signAllTransactions(txs);
|
|
@@ -223,10 +248,14 @@ export class AnchorProvider implements Provider {
|
|
// (the json RPC does not support any shorter than "confirmed" for 'getTransaction')
|
|
// (the json RPC does not support any shorter than "confirmed" for 'getTransaction')
|
|
// because that will see the tx sent with `sendAndConfirmRawTransaction` no matter which
|
|
// because that will see the tx sent with `sendAndConfirmRawTransaction` no matter which
|
|
// commitment `sendAndConfirmRawTransaction` used
|
|
// commitment `sendAndConfirmRawTransaction` used
|
|
- const failedTx = await this.connection.getTransaction(
|
|
|
|
- bs58.encode(tx.signature!),
|
|
|
|
- { commitment: "confirmed" }
|
|
|
|
|
|
+ const txSig = bs58.encode(
|
|
|
|
+ isVersionedTransaction(tx)
|
|
|
|
+ ? tx.signatures?.[0] || new Uint8Array()
|
|
|
|
+ : tx.signature ?? new Uint8Array()
|
|
);
|
|
);
|
|
|
|
+ const failedTx = await this.connection.getTransaction(txSig, {
|
|
|
|
+ commitment: "confirmed",
|
|
|
|
+ });
|
|
if (!failedTx) {
|
|
if (!failedTx) {
|
|
throw err;
|
|
throw err;
|
|
} else {
|
|
} else {
|
|
@@ -253,29 +282,42 @@ export class AnchorProvider implements Provider {
|
|
* @param opts Transaction confirmation options.
|
|
* @param opts Transaction confirmation options.
|
|
*/
|
|
*/
|
|
async simulate(
|
|
async simulate(
|
|
- tx: Transaction,
|
|
|
|
|
|
+ tx: Transaction | VersionedTransaction,
|
|
signers?: Signer[],
|
|
signers?: Signer[],
|
|
commitment?: Commitment,
|
|
commitment?: Commitment,
|
|
includeAccounts?: boolean | PublicKey[]
|
|
includeAccounts?: boolean | PublicKey[]
|
|
): Promise<SuccessfulTxSimulationResponse> {
|
|
): Promise<SuccessfulTxSimulationResponse> {
|
|
- tx.feePayer = tx.feePayer || this.wallet.publicKey;
|
|
|
|
-
|
|
|
|
- tx.recentBlockhash = (
|
|
|
|
|
|
+ let recentBlockhash = (
|
|
await this.connection.getLatestBlockhash(
|
|
await this.connection.getLatestBlockhash(
|
|
commitment ?? this.connection.commitment
|
|
commitment ?? this.connection.commitment
|
|
)
|
|
)
|
|
).blockhash;
|
|
).blockhash;
|
|
|
|
|
|
- if (signers) {
|
|
|
|
- tx = await this.wallet.signTransaction(tx);
|
|
|
|
|
|
+ let result: RpcResponseAndContext<SimulatedTransactionResponse>;
|
|
|
|
+ if (isVersionedTransaction(tx)) {
|
|
|
|
+ if (signers) {
|
|
|
|
+ tx.sign(signers);
|
|
|
|
+ tx = await this.wallet.signTransaction(tx);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Doesn't support includeAccounts which has been changed to something
|
|
|
|
+ // else in later versions of this function.
|
|
|
|
+ result = await this.connection.simulateTransaction(tx, { commitment });
|
|
|
|
+ } else {
|
|
|
|
+ tx.feePayer = tx.feePayer || this.wallet.publicKey;
|
|
|
|
+ tx.recentBlockhash = recentBlockhash;
|
|
|
|
+
|
|
|
|
+ if (signers) {
|
|
|
|
+ tx = await this.wallet.signTransaction(tx);
|
|
|
|
+ }
|
|
|
|
+ result = await simulateTransaction(
|
|
|
|
+ this.connection,
|
|
|
|
+ tx,
|
|
|
|
+ signers,
|
|
|
|
+ commitment,
|
|
|
|
+ includeAccounts
|
|
|
|
+ );
|
|
}
|
|
}
|
|
- const result = await simulateTransaction(
|
|
|
|
- this.connection,
|
|
|
|
- tx,
|
|
|
|
- signers,
|
|
|
|
- commitment,
|
|
|
|
- includeAccounts
|
|
|
|
- );
|
|
|
|
|
|
|
|
if (result.value.err) {
|
|
if (result.value.err) {
|
|
throw new SimulateError(result.value);
|
|
throw new SimulateError(result.value);
|
|
@@ -301,10 +343,15 @@ export type SendTxRequest = {
|
|
|
|
|
|
/**
|
|
/**
|
|
* Wallet interface for objects that can be used to sign provider transactions.
|
|
* Wallet interface for objects that can be used to sign provider transactions.
|
|
|
|
+ * VersionedTransactions sign everything at once
|
|
*/
|
|
*/
|
|
export interface Wallet {
|
|
export interface Wallet {
|
|
- signTransaction(tx: Transaction): Promise<Transaction>;
|
|
|
|
- signAllTransactions(txs: Transaction[]): Promise<Transaction[]>;
|
|
|
|
|
|
+ signTransaction<T extends Transaction | VersionedTransaction>(
|
|
|
|
+ tx: T
|
|
|
|
+ ): Promise<T>;
|
|
|
|
+ signAllTransactions<T extends Transaction | VersionedTransaction>(
|
|
|
|
+ txs: T[]
|
|
|
|
+ ): Promise<T[]>;
|
|
publicKey: PublicKey;
|
|
publicKey: PublicKey;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -312,7 +359,7 @@ export interface Wallet {
|
|
// a better error if 'confirmTransaction` returns an error status
|
|
// a better error if 'confirmTransaction` returns an error status
|
|
async function sendAndConfirmRawTransaction(
|
|
async function sendAndConfirmRawTransaction(
|
|
connection: Connection,
|
|
connection: Connection,
|
|
- rawTransaction: Buffer,
|
|
|
|
|
|
+ rawTransaction: Buffer | Uint8Array,
|
|
options?: ConfirmOptions
|
|
options?: ConfirmOptions
|
|
): Promise<TransactionSignature> {
|
|
): Promise<TransactionSignature> {
|
|
const sendOptions = options && {
|
|
const sendOptions = options && {
|