mango-v4/ts/client/src/utils/rpc.ts

125 lines
3.1 KiB
TypeScript

import { AnchorProvider } from '@coral-xyz/anchor';
import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet';
import {
AddressLookupTableAccount,
ComputeBudgetProgram,
MessageV0,
Signer,
TransactionInstruction,
VersionedTransaction,
} from '@solana/web3.js';
export async function sendTransaction(
provider: AnchorProvider,
ixs: TransactionInstruction[],
alts: AddressLookupTableAccount[],
opts: any = {},
): Promise<string> {
const connection = provider.connection;
const latestBlockhash = await connection.getLatestBlockhash(
opts.preflightCommitment ??
provider.opts.preflightCommitment ??
'finalized',
);
const payer = (provider as AnchorProvider).wallet;
if (opts.prioritizationFee) {
ixs = [createComputeBudgetIx(opts.prioritizationFee), ...ixs];
}
const message = MessageV0.compile({
payerKey: (provider as AnchorProvider).wallet.publicKey,
instructions: ixs,
recentBlockhash: latestBlockhash.blockhash,
addressLookupTableAccounts: alts,
});
let vtx = new VersionedTransaction(message);
if (opts?.additionalSigners?.length) {
vtx.sign([...opts?.additionalSigners]);
}
if (
typeof payer.signTransaction === 'function' &&
!(payer instanceof NodeWallet)
) {
vtx = (await payer.signTransaction(
vtx as any,
)) as unknown as VersionedTransaction;
} else {
// Maybe this path is only correct for NodeWallet?
vtx.sign([(payer as any).payer as Signer]);
}
const signature = await connection.sendRawTransaction(vtx.serialize(), {
skipPreflight: true, // mergedOpts.skipPreflight,
});
// const signature = await connection.sendTransactionss(
// vtx as any as VersionedTransaction,
// {
// skipPreflight: true,
// },
// );
if (opts.postSendTxCallback) {
try {
opts.postSendTxCallback({ txid: signature });
} catch (e) {
console.warn(`postSendTxCallback error ${e}`);
}
}
const txConfirmationCommitment = opts.txConfirmationCommitment ?? 'processed';
let status: any;
if (
latestBlockhash.blockhash != null &&
latestBlockhash.lastValidBlockHeight != null
) {
status = (
await connection.confirmTransaction(
{
signature: signature,
blockhash: latestBlockhash.blockhash,
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
},
txConfirmationCommitment,
)
).value;
} else {
status = (
await connection.confirmTransaction(signature, txConfirmationCommitment)
).value;
}
if (status.err) {
console.warn('Tx status: ', status);
throw new MangoError({
txid: signature,
message: `${JSON.stringify(status)}`,
});
}
return signature;
}
export const createComputeBudgetIx = (
microLamports: number,
): TransactionInstruction => {
const computeBudgetIx = ComputeBudgetProgram.setComputeUnitPrice({
microLamports,
});
return computeBudgetIx;
};
class MangoError extends Error {
message: string;
txid: string;
constructor({ txid, message }) {
super();
this.message = message;
this.txid = txid;
}
}