UNPKG

@openocean.finance/widget-sdk

Version:

OpenOcean Any-to-Any Cross-Chain-Swap SDK

168 lines 9.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.UTXOStepExecutor = void 0; const core_1 = require("@bigmi/core"); const widget_types_1 = require("@openocean.finance/widget-types"); const bitcoinjs_lib_1 = require("bitcoinjs-lib"); 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 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 getUTXOPublicClient_js_1 = require("./getUTXOPublicClient.js"); const parseUTXOErrors_js_1 = require("./parseUTXOErrors.js"); class UTXOStepExecutor extends BaseStepExecutor_js_1.BaseStepExecutor { client; constructor(options) { super(options); this.client = options.client; } checkClient = (step) => { if (this.client.account?.address !== step.action.fromAddress) { throw new errors_js_1.TransactionError(constants_js_1.OpenOceanErrorCode.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, }); const publicClient = await (0, getUTXOPublicClient_js_1.getUTXOPublicClient)(widget_types_1.ChainId.BTC); if (process.status !== 'DONE') { try { let txHash; let txHex; if (process.txHash) { this.checkClient(step); txHash = process.txHash; txHex = process.txHex; } else { process = this.statusManager.updateProcess(step, process.type, 'STARTED'); await (0, checkBalance_js_1.checkBalance)(this.client.account.address, 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.OpenOceanErrorCode.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.OpenOceanErrorCode.TransactionUnprepared, 'Unable to prepare transaction.'); } this.checkClient(step); const psbtHex = transactionRequest.data; const psbt = bitcoinjs_lib_1.Psbt.fromHex(psbtHex, { network: bitcoinjs_lib_1.networks.bitcoin }); const inputsToSign = Array.from(psbt.data.inputs .reduce((map, input, index) => { const accountAddress = input.witnessUtxo ? bitcoinjs_lib_1.address.fromOutputScript(input.witnessUtxo.script, bitcoinjs_lib_1.networks.bitcoin) : this.client.account?.address; if (map.has(accountAddress)) { map.get(accountAddress).signingIndexes.push(index); } else { map.set(accountAddress, { address: accountAddress, sigHash: 1, signingIndexes: [index], }); } return map; }, new Map()) .values()); const signedPsbtHex = await (0, viem_1.withTimeout)(() => (0, core_1.signPsbt)(this.client, { psbt: psbtHex, inputsToSign: inputsToSign, finalize: false, }), { timeout: 600_000, errorInstance: new errors_js_1.TransactionError(constants_js_1.OpenOceanErrorCode.TransactionExpired, 'Transaction has expired.'), }); const signedPsbt = bitcoinjs_lib_1.Psbt.fromHex(signedPsbtHex).finalizeAllInputs(); txHex = signedPsbt.extractTransaction().toHex(); txHash = await publicClient.sendUTXOTransaction({ hex: txHex, }); process = this.statusManager.updateProcess(step, process.type, 'PENDING', { txHash: txHash, txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${txHash}`, txHex, }); } let replacementReason; const transaction = await (0, core_1.waitForTransaction)(publicClient, { txId: txHash, txHex, senderAddress: this.client.account?.address, onReplaced: (response) => { replacementReason = response.reason; process = this.statusManager.updateProcess(step, process.type, 'PENDING', { txHash: response.transaction.txid, txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${response.transaction.txid}`, }); }, }); if (replacementReason === 'cancelled') { throw new errors_js_1.TransactionError(constants_js_1.OpenOceanErrorCode.TransactionCanceled, 'User canceled transaction.'); } if (transaction.txid !== txHash) { process = this.statusManager.updateProcess(step, process.type, 'PENDING', { txHash: transaction.txid, txLink: `${fromChain.metamask.blockExplorerUrls[0]}tx/${transaction.txid}`, }); } if (isBridgeExecution) { process = this.statusManager.updateProcess(step, process.type, 'DONE'); } } catch (e) { const error = await (0, parseUTXOErrors_js_1.parseUTXOErrors)(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, 10_000); return step; }; } exports.UTXOStepExecutor = UTXOStepExecutor; //# sourceMappingURL=UTXOStepExecutor.js.map