@drift-labs/sdk
Version:
SDK for Drift Protocol
104 lines (103 loc) • 5.55 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTransactionError = exports.getTransactionErrorFromTxSig = exports.throwTransactionError = void 0;
const web3_js_1 = require("@solana/web3.js");
const config_1 = require("../config");
/**
* The new getTransaction method expects a Finality type instead of a Commitment type. The only options for Finality are 'confirmed' and 'finalized'.
* @param commitment
* @returns
*/
const commitmentToFinality = (commitment) => {
switch (commitment) {
case 'confirmed':
return 'confirmed';
case 'finalized':
return 'finalized';
default:
throw new Error(`Invalid commitment when reporting transaction error. The commitment must be 'confirmed' or 'finalized' but was given '${commitment}'. If you're using this commitment for a specific reason, you may need to roll your own logic here.`);
}
};
const getTransactionResult = async (txSig, connection, commitment) => {
const finality = commitmentToFinality(commitment || connection.commitment || config_1.DEFAULT_CONFIRMATION_OPTS.commitment);
return await connection.getTransaction(txSig, {
maxSupportedTransactionVersion: 0,
commitment: finality,
});
};
const getTransactionResultWithRetry = async (txSig, connection, commitment) => {
const start = Date.now();
const retryTimeout = 3000; // Timeout after 3 seconds
const retryInterval = 800; // Retry with 800ms interval
const retryCount = 3; // Retry 3 times
let currentCount = 0;
let transactionResult = await getTransactionResult(txSig, connection, commitment);
// Retry 3 times or until timeout as long as we don't have a result yet
while (!transactionResult &&
Date.now() - start < retryTimeout &&
currentCount < retryCount) {
// Sleep for 1 second :: Do this first so that we don't run the first loop immediately after the initial fetch above
await new Promise((resolve) => setTimeout(resolve, retryInterval));
transactionResult = await getTransactionResult(txSig, connection, commitment);
currentCount++;
}
return transactionResult;
};
/**
* THROWS if there is an error
*
* Should only be used for a txSig that is confirmed has an error. There is a race-condition where sometimes the transaction is not instantly available to fetch after the confirmation has already failed with an error, so this method has retry logic which we don't want to do wastefully. This method will throw a generic error if it can't get the transaction result after a retry period.
* @param txSig
* @param connection
* @returns
*/
const throwTransactionError = async (txSig, connection, commitment) => {
const err = await (0, exports.getTransactionErrorFromTxSig)(txSig, connection, commitment);
if (err) {
throw err;
}
return;
};
exports.throwTransactionError = throwTransactionError;
/**
* RETURNS an error if there is one
*
* Should only be used for a txSig that is confirmed has an error. There is a race-condition where sometimes the transaction is not instantly available to fetch after the confirmation has already failed with an error, so this method has retry logic which we don't want to do wastefully. This method will throw a generic error if it can't get the transaction result after a retry period.
* @param txSig
* @param connection
* @returns
*/
const getTransactionErrorFromTxSig = async (txSig, connection, commitment) => {
var _a;
const transactionResult = await getTransactionResultWithRetry(txSig, connection, commitment);
if (!transactionResult) {
// Throw a generic error because we couldn't get the transaction result for the given txSig
return new web3_js_1.SendTransactionError({
action: 'send',
signature: txSig,
transactionMessage: `Transaction Failed`,
});
}
if (!((_a = transactionResult === null || transactionResult === void 0 ? void 0 : transactionResult.meta) === null || _a === void 0 ? void 0 : _a.err)) {
// Assume that the transaction was successful and we are here erroneously because we have a result with no error
return;
}
return (0, exports.getTransactionError)(transactionResult);
};
exports.getTransactionErrorFromTxSig = getTransactionErrorFromTxSig;
const getTransactionError = (transactionResult) => {
var _a, _b, _c, _d, _e, _f;
if (!((_a = transactionResult === null || transactionResult === void 0 ? void 0 : transactionResult.meta) === null || _a === void 0 ? void 0 : _a.err)) {
return;
}
const logs = (_c = (_b = transactionResult === null || transactionResult === void 0 ? void 0 : transactionResult.meta) === null || _b === void 0 ? void 0 : _b.logMessages) !== null && _c !== void 0 ? _c : ['No logs'];
const lastLog = logs[logs.length - 1];
const friendlyMessage = (_d = lastLog === null || lastLog === void 0 ? void 0 : lastLog.match(/(failed:) (.+)/)) === null || _d === void 0 ? void 0 : _d[2];
return new web3_js_1.SendTransactionError({
action: 'send',
signature: (_f = (_e = transactionResult === null || transactionResult === void 0 ? void 0 : transactionResult.transaction) === null || _e === void 0 ? void 0 : _e.signatures) === null || _f === void 0 ? void 0 : _f[0],
transactionMessage: `Transaction Failed${friendlyMessage ? `: ${friendlyMessage}` : ''}`,
logs,
});
};
exports.getTransactionError = getTransactionError;
;