@lifi/sdk
Version:
LI.FI Any-to-Any Cross-Chain-Swap SDK
125 lines • 7.37 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.SolanaStepExecutor = void 0;
const web3_js_1 = require("@solana/web3.js");
const viem_1 = require("viem");
const config_js_1 = require("../../config.js");
const constants_js_1 = require("../../errors/constants.js");
const errors_js_1 = require("../../errors/errors.js");
const api_js_1 = require("../../services/api.js");
const base64ToUint8Array_js_1 = require("../../utils/base64ToUint8Array.js");
const BaseStepExecutor_js_1 = require("../BaseStepExecutor.js");
const checkBalance_js_1 = require("../checkBalance.js");
const stepComparison_js_1 = require("../stepComparison.js");
const waitForDestinationChainTransaction_js_1 = require("../waitForDestinationChainTransaction.js");
const connection_js_1 = require("./connection.js");
const parseSolanaErrors_js_1 = require("./parseSolanaErrors.js");
const sendAndConfirmTransaction_js_1 = require("./sendAndConfirmTransaction.js");
class SolanaStepExecutor extends BaseStepExecutor_js_1.BaseStepExecutor {
walletAdapter;
constructor(options) {
super(options);
this.walletAdapter = options.walletAdapter;
}
checkWalletAdapter = (step) => {
if (this.walletAdapter.publicKey.toString() !== step.action.fromAddress) {
throw new errors_js_1.TransactionError(constants_js_1.LiFiErrorCode.WalletChangedDuringExecution, 'The wallet address that requested the quote does not match the wallet address attempting to sign the transaction.');
}
};
executeStep = async (step) => {
step.execution = this.statusManager.initExecutionObject(step);
const fromChain = await config_js_1.config.getChainById(step.action.fromChainId);
const toChain = await config_js_1.config.getChainById(step.action.toChainId);
const isBridgeExecution = fromChain.id !== toChain.id;
const currentProcessType = isBridgeExecution ? 'CROSS_CHAIN' : 'SWAP';
let process = this.statusManager.findOrCreateProcess({
step,
type: currentProcessType,
chainId: fromChain.id,
});
if (process.status !== 'DONE') {
try {
process = this.statusManager.updateProcess(step, process.type, 'STARTED');
await (0, checkBalance_js_1.checkBalance)(this.walletAdapter.publicKey.toString(), step);
if (!step.transactionRequest) {
const { execution, ...stepBase } = step;
const updatedStep = await (0, api_js_1.getStepTransaction)(stepBase);
const comparedStep = await (0, stepComparison_js_1.stepComparison)(this.statusManager, step, updatedStep, this.allowUserInteraction, this.executionOptions);
Object.assign(step, {
...comparedStep,
execution: step.execution,
});
}
if (!step.transactionRequest?.data) {
throw new errors_js_1.TransactionError(constants_js_1.LiFiErrorCode.TransactionUnprepared, 'Unable to prepare transaction.');
}
process = this.statusManager.updateProcess(step, process.type, 'ACTION_REQUIRED');
if (!this.allowUserInteraction) {
return step;
}
let transactionRequest = {
data: step.transactionRequest.data,
};
if (this.executionOptions?.updateTransactionRequestHook) {
const customizedTransactionRequest = await this.executionOptions.updateTransactionRequestHook({
requestType: 'transaction',
...transactionRequest,
});
transactionRequest = {
...transactionRequest,
...customizedTransactionRequest,
};
}
if (!transactionRequest.data) {
throw new errors_js_1.TransactionError(constants_js_1.LiFiErrorCode.TransactionUnprepared, 'Unable to prepare transaction.');
}
const versionedTransaction = web3_js_1.VersionedTransaction.deserialize((0, base64ToUint8Array_js_1.base64ToUint8Array)(transactionRequest.data));
this.checkWalletAdapter(step);
const signedTx = await (0, viem_1.withTimeout)(() => this.walletAdapter.signTransaction(versionedTransaction), {
timeout: 120_000,
errorInstance: new errors_js_1.TransactionError(constants_js_1.LiFiErrorCode.TransactionExpired, 'Transaction has expired: blockhash is no longer recent enough.'),
});
process = this.statusManager.updateProcess(step, process.type, 'PENDING');
const simulationResult = await (0, connection_js_1.callSolanaWithRetry)((connection) => connection.simulateTransaction(signedTx, {
commitment: 'confirmed',
replaceRecentBlockhash: true,
}));
if (simulationResult.value.err) {
throw new errors_js_1.TransactionError(constants_js_1.LiFiErrorCode.TransactionSimulationFailed, 'Transaction simulation failed');
}
const confirmedTx = await (0, sendAndConfirmTransaction_js_1.sendAndConfirmTransaction)(signedTx);
if (!confirmedTx.signatureResult) {
throw new errors_js_1.TransactionError(constants_js_1.LiFiErrorCode.TransactionExpired, 'Transaction has expired: The block height has exceeded the maximum allowed limit.');
}
if (confirmedTx.signatureResult.err) {
const reason = typeof confirmedTx.signatureResult.err === 'object'
? JSON.stringify(confirmedTx.signatureResult.err)
: confirmedTx.signatureResult.err;
throw new errors_js_1.TransactionError(constants_js_1.LiFiErrorCode.TransactionFailed, `Transaction failed: ${reason}`);
}
process = this.statusManager.updateProcess(step, process.type, 'PENDING', {
txHash: confirmedTx.txSignature,
txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${confirmedTx.txSignature}`,
});
if (isBridgeExecution) {
process = this.statusManager.updateProcess(step, process.type, 'DONE');
}
}
catch (e) {
const error = await (0, parseSolanaErrors_js_1.parseSolanaErrors)(e, step, process);
process = this.statusManager.updateProcess(step, process.type, 'FAILED', {
error: {
message: error.cause.message,
code: error.code,
},
});
this.statusManager.updateExecution(step, 'FAILED');
throw error;
}
}
await (0, waitForDestinationChainTransaction_js_1.waitForDestinationChainTransaction)(step, process, fromChain, toChain, this.statusManager);
return step;
};
}
exports.SolanaStepExecutor = SolanaStepExecutor;
//# sourceMappingURL=SolanaStepExecutor.js.map
;