@kamino-finance/klend-sdk
Version:
Typescript SDK for interacting with the Kamino Lending (klend) protocol
234 lines • 9.85 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.getComputeBudgetAndPriorityFeeIxs = exports.getLookupTableAccount = exports.buildVersionedTransactionSync = exports.buildVersionedTransaction = void 0;
exports.buildAndSendTxnWithLogs = buildAndSendTxnWithLogs;
exports.buildAndSendTxn = buildAndSendTxn;
exports.sendAndConfirmVersionedTransaction = sendAndConfirmVersionedTransaction;
exports.simulateTxn = simulateTxn;
exports.buildComputeBudgetIx = buildComputeBudgetIx;
exports.sendTransactionV0 = sendTransactionV0;
exports.simulateTransactionV0 = simulateTransactionV0;
exports.getLookupTableAccountsFromAddresses = getLookupTableAccountsFromAddresses;
exports.getLookupTableAccounts = getLookupTableAccounts;
exports.notEmpty = notEmpty;
exports.uniqueAccountsWithProgramIds = uniqueAccountsWithProgramIds;
exports.removeBudgetIxs = removeBudgetIxs;
const web3_js_1 = require("@solana/web3.js");
const errors_1 = require("../idl_codegen/errors");
const utils_1 = require("../classes/utils");
const kliquidity_sdk_1 = require("@kamino-finance/kliquidity-sdk");
const pubkey_1 = require("./pubkey");
async function buildAndSendTxnWithLogs(c, tx, owner, signers, withLogsIfSuccess = false, withDescription = '', throwOnError = false // TODO(error-surfacing): the "recovery" logic is broken/outdated + the "hide error" behavior seems wrong in general - migrate to "just throw"
) {
tx.sign([owner, ...signers]);
try {
const sig = await sendAndConfirmVersionedTransaction(c, tx, 'confirmed', {
preflightCommitment: 'processed',
});
console.log('Transaction Hash:', withDescription, sig);
if (withLogsIfSuccess) {
await (0, utils_1.sleep)(1000);
const res = await c.getTransaction(sig, {
commitment: 'confirmed',
maxSupportedTransactionVersion: 6,
});
console.log('Transaction Logs:\n', res?.meta?.logMessages);
}
return sig;
}
catch (e) {
if (throwOnError) {
throw e;
}
console.log(e);
process.stdout.write(e.logs.toString());
const sig = e.toString().split(' failed ')[0].split('Transaction ')[1];
const res = await c.getTransaction(sig, {
commitment: 'confirmed',
maxSupportedTransactionVersion: 6,
});
console.log('Txn', res.meta.logMessages);
return sig;
}
}
async function buildAndSendTxn(c, owner, ixs, signers, lutAddresses = [], description = '') {
const tx = await (0, exports.buildVersionedTransaction)(c, owner.publicKey, ixs, lutAddresses);
return await buildAndSendTxnWithLogs(c, tx, owner, signers, true, description);
}
async function sendAndConfirmVersionedTransaction(c, tx, commitment = 'confirmed', sendTransactionOptions = { preflightCommitment: 'processed' }) {
const defaultOptions = { skipPreflight: true };
const txId = await c.sendTransaction(tx, { ...defaultOptions, ...sendTransactionOptions });
const latestBlockHash = await c.getLatestBlockhash('finalized');
const t = await c.confirmTransaction({
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature: txId,
}, commitment);
if (t.value && t.value.err) {
const txDetails = await c.getTransaction(txId, {
maxSupportedTransactionVersion: 0,
commitment: 'confirmed',
});
if (txDetails) {
throw { err: txDetails.meta?.err, logs: txDetails.meta?.logMessages || [] };
}
throw t.value.err;
}
return txId;
}
async function simulateTxn(c, tx, owner, signers) {
const { blockhash } = await c.getLatestBlockhash();
tx.recentBlockhash = blockhash;
tx.feePayer = owner.publicKey;
try {
const simulation = await c.simulateTransaction(tx, [owner, ...signers]);
console.log('Transaction Hash:', simulation);
}
catch (e) {
console.log(e);
process.stdout.write(e.logs.toString());
const sig = e.toString().split(' failed ')[0].split('Transaction ')[1];
const res = await c.getTransaction(sig, {
commitment: 'confirmed',
});
console.log('Txn', res.meta.logMessages);
return sig;
}
}
function buildComputeBudgetIx(units) {
return web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units });
}
/**
* Send a transaction with optional address lookup tables
* Translates anchor errors into anchor error types
* @param connection
* @param payer
* @param instructions
* @param lookupTables
*/
async function sendTransactionV0(connection, payer, instructions, lookupTables = undefined, options) {
const recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
const messageV0 = new web3_js_1.TransactionMessage({
payerKey: payer.publicKey,
recentBlockhash,
instructions,
}).compileToV0Message(lookupTables);
const tx = new web3_js_1.VersionedTransaction(messageV0);
tx.sign([payer]);
try {
return await connection.sendTransaction(tx, options);
}
catch (err) {
throw (0, errors_1.fromTxError)(err) ?? err;
}
}
async function simulateTransactionV0(connection, payer, instructions, lookupTables = undefined) {
const recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
const messageV0 = new web3_js_1.TransactionMessage({
payerKey: payer.publicKey,
recentBlockhash,
instructions,
}).compileToV0Message(lookupTables);
const tx = new web3_js_1.VersionedTransaction(messageV0);
tx.sign([payer]);
try {
return await connection.simulateTransaction(tx);
}
catch (err) {
throw (0, errors_1.fromTxError)(err) ?? err;
}
}
const buildVersionedTransaction = async (connection, payer, instructions, lookupTables = []) => {
const blockhash = await connection.getLatestBlockhash('confirmed').then((res) => res.blockhash);
const lookupTablesAccounts = await Promise.all(lookupTables.map((address) => {
return (0, exports.getLookupTableAccount)(connection, address);
}));
const messageV0 = new web3_js_1.TransactionMessage({
payerKey: payer,
recentBlockhash: blockhash,
instructions,
}).compileToV0Message(lookupTablesAccounts.filter(notEmpty));
return new web3_js_1.VersionedTransaction(messageV0);
};
exports.buildVersionedTransaction = buildVersionedTransaction;
async function getLookupTableAccountsFromAddresses(connection, addresses) {
const lookupTablesAccounts = await Promise.all(addresses.map((address) => {
return (0, exports.getLookupTableAccount)(connection, address);
}));
return lookupTablesAccounts.filter((account) => account !== null);
}
const buildVersionedTransactionSync = (payer, instructions, blockhash, lookupTables = []) => {
const messageV0 = new web3_js_1.TransactionMessage({
payerKey: payer,
recentBlockhash: blockhash,
instructions,
}).compileToV0Message(lookupTables.filter(notEmpty));
return new web3_js_1.VersionedTransaction(messageV0);
};
exports.buildVersionedTransactionSync = buildVersionedTransactionSync;
const getLookupTableAccount = async (connection, address) => {
return connection.getAddressLookupTable(address).then((res) => res.value);
};
exports.getLookupTableAccount = getLookupTableAccount;
async function getLookupTableAccounts(connection, addresses) {
const lookupTableAccounts = [];
const accountInfos = await (0, kliquidity_sdk_1.batchFetch)(addresses, (batch) => connection.getMultipleAccountsInfo(batch));
for (let i = 0; i < addresses.length; i++) {
const info = accountInfos[i];
if (!info) {
throw new Error(`Lookup table ${addresses[i]} is not found`);
}
lookupTableAccounts.push(new web3_js_1.AddressLookupTableAccount({
key: addresses[i],
state: web3_js_1.AddressLookupTableAccount.deserialize(info.data),
}));
}
return lookupTableAccounts;
}
const getComputeBudgetAndPriorityFeeIxs = (units, priorityFeeLamports) => {
const ixs = [];
ixs.push(web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units }));
if (priorityFeeLamports && priorityFeeLamports.gt(0)) {
const unitPrice = priorityFeeLamports.mul(10 ** 6).div(units);
ixs.push(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: BigInt(unitPrice.floor().toString()) }));
}
return ixs;
};
exports.getComputeBudgetAndPriorityFeeIxs = getComputeBudgetAndPriorityFeeIxs;
// filters null values from array and make typescript happy
function notEmpty(value) {
if (value === null || value === undefined) {
return false;
}
//
// eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
const testDummy = value;
return true;
}
function uniqueAccountsWithProgramIds(ixs, addressLookupTables = []) {
let luts;
if (addressLookupTables.length > 0 && addressLookupTables[0] instanceof web3_js_1.AddressLookupTableAccount) {
luts = addressLookupTables.map((lut) => lut.key);
}
else {
luts = addressLookupTables;
}
const uniqueAccounts = new pubkey_1.PublicKeySet(luts);
ixs.forEach((ix) => {
uniqueAccounts.add(ix.programId);
ix.keys.forEach((key) => {
uniqueAccounts.add(key.pubkey);
});
});
return uniqueAccounts.toArray();
}
function removeBudgetIxs(ixs) {
return ixs.filter((ix) => {
const { programId } = ix;
if (programId.equals(web3_js_1.ComputeBudgetProgram.programId)) {
return false;
}
return true;
});
}
//# sourceMappingURL=instruction.js.map
;