Simple versioned transaction support (#2427)
This commit is contained in:
parent
1dc16d6642
commit
30083bd83c
|
@ -23,6 +23,7 @@ The minor version will be incremented upon a breaking change and the patch versi
|
||||||
- client: Add support for multithreading to the rust client: use flag `--multithreaded` ([#2321](https://github.com/coral-xyz/anchor/pull/2321)).
|
- client: Add support for multithreading to the rust client: use flag `--multithreaded` ([#2321](https://github.com/coral-xyz/anchor/pull/2321)).
|
||||||
- client: Add `async_rpc` a method which returns a nonblocking solana rpc client ([2322](https://github.com/coral-xyz/anchor/pull/2322)).
|
- client: Add `async_rpc` a method which returns a nonblocking solana rpc client ([2322](https://github.com/coral-xyz/anchor/pull/2322)).
|
||||||
- avm, cli: Use the `rustls-tls` feature of `reqwest` so that users don't need OpenSSL installed ([#2385](https://github.com/coral-xyz/anchor/pull/2385)).
|
- avm, cli: Use the `rustls-tls` feature of `reqwest` so that users don't need OpenSSL installed ([#2385](https://github.com/coral-xyz/anchor/pull/2385)).
|
||||||
|
- ts: Add `VersionedTransaction` support. Methods in the `Provider` class and `Wallet` interface now use the argument `tx: Transaction | VersionedTransaction` ([2427](https://github.com/coral-xyz/anchor/pull/2427)).
|
||||||
- cli: Add `--arch sbf` option to compile programs using `cargo build-sbf` ([#2398](https://github.com/coral-xyz/anchor/pull/2398)).
|
- cli: Add `--arch sbf` option to compile programs using `cargo build-sbf` ([#2398](https://github.com/coral-xyz/anchor/pull/2398)).
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
|
@ -6,6 +6,8 @@ import {
|
||||||
SystemProgram,
|
SystemProgram,
|
||||||
Message,
|
Message,
|
||||||
VersionedTransaction,
|
VersionedTransaction,
|
||||||
|
AddressLookupTableProgram,
|
||||||
|
TransactionMessage,
|
||||||
} from "@solana/web3.js";
|
} from "@solana/web3.js";
|
||||||
import {
|
import {
|
||||||
TOKEN_PROGRAM_ID,
|
TOKEN_PROGRAM_ID,
|
||||||
|
@ -61,6 +63,151 @@ const miscTest = (
|
||||||
assert.strictEqual(dataAccount.data, 99);
|
assert.strictEqual(dataAccount.data, 99);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Can send VersionedTransaction", async () => {
|
||||||
|
// Create the lookup table
|
||||||
|
const recentSlot = await provider.connection.getSlot();
|
||||||
|
const [loookupTableInstruction, lookupTableAddress] =
|
||||||
|
AddressLookupTableProgram.createLookupTable({
|
||||||
|
authority: provider.publicKey,
|
||||||
|
payer: provider.publicKey,
|
||||||
|
recentSlot,
|
||||||
|
});
|
||||||
|
const extendInstruction = AddressLookupTableProgram.extendLookupTable({
|
||||||
|
payer: provider.publicKey,
|
||||||
|
authority: provider.publicKey,
|
||||||
|
lookupTable: lookupTableAddress,
|
||||||
|
addresses: [provider.publicKey, SystemProgram.programId],
|
||||||
|
});
|
||||||
|
let createLookupTableTx = new VersionedTransaction(
|
||||||
|
new TransactionMessage({
|
||||||
|
instructions: [loookupTableInstruction, extendInstruction],
|
||||||
|
payerKey: program.provider.publicKey,
|
||||||
|
recentBlockhash: (await provider.connection.getLatestBlockhash())
|
||||||
|
.blockhash,
|
||||||
|
}).compileToV0Message()
|
||||||
|
);
|
||||||
|
type SendParams = Parameters<typeof provider.sendAndConfirm>;
|
||||||
|
const testThis: SendParams = [
|
||||||
|
new VersionedTransaction(
|
||||||
|
new TransactionMessage({
|
||||||
|
instructions: [loookupTableInstruction, extendInstruction],
|
||||||
|
payerKey: program.provider.publicKey,
|
||||||
|
recentBlockhash: (await provider.connection.getLatestBlockhash())
|
||||||
|
.blockhash,
|
||||||
|
}).compileToV0Message()
|
||||||
|
),
|
||||||
|
];
|
||||||
|
await provider.sendAndConfirm(createLookupTableTx, [], {
|
||||||
|
skipPreflight: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use the lookup table in a transaction
|
||||||
|
const transferAmount = 1_000_000;
|
||||||
|
const lookupTableAccount = await provider.connection
|
||||||
|
.getAddressLookupTable(lookupTableAddress)
|
||||||
|
.then((res) => res.value);
|
||||||
|
const target = Keypair.generate();
|
||||||
|
let transferInstruction = SystemProgram.transfer({
|
||||||
|
fromPubkey: provider.publicKey,
|
||||||
|
lamports: transferAmount,
|
||||||
|
toPubkey: target.publicKey,
|
||||||
|
});
|
||||||
|
let transferUsingLookupTx = new VersionedTransaction(
|
||||||
|
new TransactionMessage({
|
||||||
|
instructions: [transferInstruction],
|
||||||
|
payerKey: program.provider.publicKey,
|
||||||
|
recentBlockhash: (await provider.connection.getLatestBlockhash())
|
||||||
|
.blockhash,
|
||||||
|
}).compileToV0Message([lookupTableAccount])
|
||||||
|
);
|
||||||
|
await provider.simulate(transferUsingLookupTx, [], "processed");
|
||||||
|
await provider.sendAndConfirm(transferUsingLookupTx, [], {
|
||||||
|
skipPreflight: true,
|
||||||
|
commitment: "confirmed",
|
||||||
|
});
|
||||||
|
let newBalance = await provider.connection.getBalance(
|
||||||
|
target.publicKey,
|
||||||
|
"confirmed"
|
||||||
|
);
|
||||||
|
assert.strictEqual(newBalance, transferAmount);
|
||||||
|
|
||||||
|
// Test sendAll with versioned transaction
|
||||||
|
let oneTransferUsingLookupTx = new VersionedTransaction(
|
||||||
|
new TransactionMessage({
|
||||||
|
instructions: [
|
||||||
|
SystemProgram.transfer({
|
||||||
|
fromPubkey: provider.publicKey,
|
||||||
|
// Needed to make the transactions distinct
|
||||||
|
lamports: transferAmount + 1,
|
||||||
|
toPubkey: target.publicKey,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
payerKey: program.provider.publicKey,
|
||||||
|
recentBlockhash: (await provider.connection.getLatestBlockhash())
|
||||||
|
.blockhash,
|
||||||
|
}).compileToV0Message([lookupTableAccount])
|
||||||
|
);
|
||||||
|
let twoTransferUsingLookupTx = new VersionedTransaction(
|
||||||
|
new TransactionMessage({
|
||||||
|
instructions: [
|
||||||
|
SystemProgram.transfer({
|
||||||
|
fromPubkey: provider.publicKey,
|
||||||
|
lamports: transferAmount,
|
||||||
|
toPubkey: target.publicKey,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
payerKey: program.provider.publicKey,
|
||||||
|
recentBlockhash: (await provider.connection.getLatestBlockhash())
|
||||||
|
.blockhash,
|
||||||
|
}).compileToV0Message([lookupTableAccount])
|
||||||
|
);
|
||||||
|
await provider.sendAll(
|
||||||
|
[{ tx: oneTransferUsingLookupTx }, { tx: twoTransferUsingLookupTx }],
|
||||||
|
{ skipPreflight: true, commitment: "confirmed" }
|
||||||
|
);
|
||||||
|
newBalance = await provider.connection.getBalance(
|
||||||
|
target.publicKey,
|
||||||
|
"confirmed"
|
||||||
|
);
|
||||||
|
assert.strictEqual(newBalance, transferAmount * 3 + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Can send VersionedTransaction with extra signatures", async () => {
|
||||||
|
// Test sending with signatures
|
||||||
|
const initSpace = 100;
|
||||||
|
const rentExemptAmount =
|
||||||
|
await provider.connection.getMinimumBalanceForRentExemption(initSpace);
|
||||||
|
|
||||||
|
const newAccount = Keypair.generate();
|
||||||
|
let createAccountIx = SystemProgram.createAccount({
|
||||||
|
fromPubkey: provider.publicKey,
|
||||||
|
lamports: rentExemptAmount,
|
||||||
|
newAccountPubkey: newAccount.publicKey,
|
||||||
|
programId: program.programId,
|
||||||
|
space: initSpace,
|
||||||
|
});
|
||||||
|
let createAccountTx = new VersionedTransaction(
|
||||||
|
new TransactionMessage({
|
||||||
|
instructions: [createAccountIx],
|
||||||
|
payerKey: provider.publicKey,
|
||||||
|
recentBlockhash: (await provider.connection.getLatestBlockhash())
|
||||||
|
.blockhash,
|
||||||
|
}).compileToV0Message()
|
||||||
|
);
|
||||||
|
await provider.simulate(createAccountTx, [], "processed");
|
||||||
|
await provider.sendAndConfirm(createAccountTx, [newAccount], {
|
||||||
|
skipPreflight: false,
|
||||||
|
commitment: "confirmed",
|
||||||
|
});
|
||||||
|
let newAccountInfo = await provider.connection.getAccountInfo(
|
||||||
|
newAccount.publicKey
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
newAccountInfo.owner.toBase58(),
|
||||||
|
program.programId.toBase58()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("Can embed programs into genesis from the Anchor.toml", async () => {
|
it("Can embed programs into genesis from the Anchor.toml", async () => {
|
||||||
const pid = new anchor.web3.PublicKey(
|
const pid = new anchor.web3.PublicKey(
|
||||||
"FtMNMKp9DZHKWUyVAsj3Q5QV8ow4P3fUPP7ZrWEQJzKr"
|
"FtMNMKp9DZHKWUyVAsj3Q5QV8ow4P3fUPP7ZrWEQJzKr"
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
import { Buffer } from "buffer";
|
import { Buffer } from "buffer";
|
||||||
import { Keypair, PublicKey, Transaction } from "@solana/web3.js";
|
import {
|
||||||
|
Keypair,
|
||||||
|
PublicKey,
|
||||||
|
Transaction,
|
||||||
|
VersionedTransaction,
|
||||||
|
} from "@solana/web3.js";
|
||||||
import { Wallet } from "./provider";
|
import { Wallet } from "./provider";
|
||||||
|
import { isVersionedTransaction } from "./utils/common.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Node only wallet.
|
* Node only wallet.
|
||||||
|
@ -30,14 +36,27 @@ export default class NodeWallet implements Wallet {
|
||||||
return new NodeWallet(payer);
|
return new NodeWallet(payer);
|
||||||
}
|
}
|
||||||
|
|
||||||
async signTransaction(tx: Transaction): Promise<Transaction> {
|
async signTransaction<T extends Transaction | VersionedTransaction>(
|
||||||
|
tx: T
|
||||||
|
): Promise<T> {
|
||||||
|
if (isVersionedTransaction(tx)) {
|
||||||
|
tx.sign([this.payer]);
|
||||||
|
} else {
|
||||||
tx.partialSign(this.payer);
|
tx.partialSign(this.payer);
|
||||||
|
}
|
||||||
|
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
async signAllTransactions(txs: Transaction[]): Promise<Transaction[]> {
|
async signAllTransactions<T extends Transaction | VersionedTransaction>(
|
||||||
|
txs: T[]
|
||||||
|
): Promise<T[]> {
|
||||||
return txs.map((t) => {
|
return txs.map((t) => {
|
||||||
|
if (isVersionedTransaction(t)) {
|
||||||
|
t.sign([this.payer]);
|
||||||
|
} else {
|
||||||
t.partialSign(this.payer);
|
t.partialSign(this.payer);
|
||||||
|
}
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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?(
|
sendAll?<T extends Transaction | VersionedTransaction>(
|
||||||
txWithSigners: { tx: Transaction; signers?: Signer[] }[],
|
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;
|
if (isVersionedTransaction(tx)) {
|
||||||
|
if (signers) {
|
||||||
|
tx.sign(signers);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tx.feePayer = tx.feePayer ?? this.wallet.publicKey;
|
||||||
tx.recentBlockhash = (
|
tx.recentBlockhash = (
|
||||||
await this.connection.getLatestBlockhash(opts.preflightCommitment)
|
await this.connection.getLatestBlockhash(opts.preflightCommitment)
|
||||||
).blockhash;
|
).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(
|
const txSig = bs58.encode(
|
||||||
bs58.encode(tx.signature!),
|
isVersionedTransaction(tx)
|
||||||
{ commitment: "confirmed" }
|
? 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(
|
async sendAll<T extends Transaction | VersionedTransaction>(
|
||||||
txWithSigners: { tx: Transaction; signers?: Signer[] }[],
|
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(
|
const recentBlockhash = (
|
||||||
opts.preflightCommitment
|
await this.connection.getLatestBlockhash(opts.preflightCommitment)
|
||||||
);
|
).blockhash;
|
||||||
|
|
||||||
let txs = txWithSigners.map((r) => {
|
let txs = txWithSigners.map((r) => {
|
||||||
let tx = r.tx;
|
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 ?? [];
|
let signers = r.signers ?? [];
|
||||||
|
|
||||||
tx.feePayer = tx.feePayer || this.wallet.publicKey;
|
tx.feePayer = tx.feePayer ?? this.wallet.publicKey;
|
||||||
|
tx.recentBlockhash = recentBlockhash;
|
||||||
tx.recentBlockhash = blockhash.blockhash;
|
|
||||||
|
|
||||||
signers.forEach((kp) => {
|
signers.forEach((kp) => {
|
||||||
tx.partialSign(kp);
|
tx.partialSign(kp);
|
||||||
});
|
});
|
||||||
|
|
||||||
return tx;
|
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(
|
const txSig = bs58.encode(
|
||||||
bs58.encode(tx.signature!),
|
isVersionedTransaction(tx)
|
||||||
{ commitment: "confirmed" }
|
? 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;
|
let recentBlockhash = (
|
||||||
|
|
||||||
tx.recentBlockhash = (
|
|
||||||
await this.connection.getLatestBlockhash(
|
await this.connection.getLatestBlockhash(
|
||||||
commitment ?? this.connection.commitment
|
commitment ?? this.connection.commitment
|
||||||
)
|
)
|
||||||
).blockhash;
|
).blockhash;
|
||||||
|
|
||||||
|
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) {
|
if (signers) {
|
||||||
tx = await this.wallet.signTransaction(tx);
|
tx = await this.wallet.signTransaction(tx);
|
||||||
}
|
}
|
||||||
const result = await simulateTransaction(
|
result = await simulateTransaction(
|
||||||
this.connection,
|
this.connection,
|
||||||
tx,
|
tx,
|
||||||
signers,
|
signers,
|
||||||
commitment,
|
commitment,
|
||||||
includeAccounts
|
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>;
|
signTransaction<T extends Transaction | VersionedTransaction>(
|
||||||
signAllTransactions(txs: Transaction[]): Promise<Transaction[]>;
|
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 && {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Transaction, VersionedTransaction } from "@solana/web3.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if being run inside a web browser,
|
* Returns true if being run inside a web browser,
|
||||||
* false if in a Node process or electron app.
|
* false if in a Node process or electron app.
|
||||||
|
@ -18,3 +20,15 @@ export function chunks<T>(array: T[], size: number): T[][] {
|
||||||
(_, index) => array.slice(index * size, (index + 1) * size)
|
(_, index) => array.slice(index * size, (index + 1) * size)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a transaction object is a VersionedTransaction or not
|
||||||
|
*
|
||||||
|
* @param tx
|
||||||
|
* @returns bool
|
||||||
|
*/
|
||||||
|
export const isVersionedTransaction = (
|
||||||
|
tx: Transaction | VersionedTransaction
|
||||||
|
): tx is VersionedTransaction => {
|
||||||
|
return "version" in tx;
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue