@openocean.finance/widget-sdk
Version:
OpenOcean Any-to-Any Cross-Chain-Swap SDK
168 lines • 9.11 kB
JavaScript
;
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