UNPKG

bitcore-wallet-service

Version:
304 lines 11.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TxProposal = void 0; const lodash_1 = __importDefault(require("lodash")); const index_1 = require("../chain/index"); const common_1 = require("../common"); const logger_1 = __importDefault(require("../logger")); const txproposal_legacy_1 = require("./txproposal_legacy"); const txproposalaction_1 = require("./txproposalaction"); const $ = require('preconditions').singleton(); const Uuid = require('uuid'); const Constants = common_1.Common.Constants, Defaults = common_1.Common.Defaults, Utils = common_1.Common.Utils; class TxProposal { constructor() { this.actions = []; } static create(opts) { opts = opts || {}; const chain = opts.chain?.toLowerCase() || index_1.ChainService.getChain(opts.coin); $.checkArgument(Utils.checkValueInCollection(opts.network, Constants.NETWORKS[chain]), `Invalid network: ${opts.network} at TxProposal.create()`); const x = new TxProposal(); if (opts.version) { $.checkArgument(opts.version >= 3); } x.version = opts.version || 3; $.checkState(x.version <= 3, 'Failed state: txp version 4 not allowed yet at TxProposal.create()'); const now = Date.now(); x.createdOn = Math.floor(now / 1000); x.id = opts.id || Uuid.v4(); x.walletId = opts.walletId; x.creatorId = opts.creatorId; x.coin = opts.coin; x.chain = chain; x.network = opts.network; x.signingMethod = opts.signingMethod; x.message = opts.message; x.payProUrl = opts.payProUrl; x.changeAddress = opts.changeAddress; x.escrowAddress = opts.escrowAddress; x.instantAcceptanceEscrow = opts.instantAcceptanceEscrow; x.outputs = (opts.outputs || []).map(output => { const out = {}; if (output.amount !== undefined) out.amount = output.amount; if (output.toAddress !== undefined) out.toAddress = output.toAddress; if (output.message !== undefined) out.message = output.message; if (output.data !== undefined) out.data = output.data; if (output.gasLimit !== undefined) out.gasLimit = output.gasLimit; if (output.script !== undefined) out.script = output.script; if (output.tag !== undefined) out.tag = output.tag; return out; }); let numOutputs = x.outputs.length; if (!opts.multiTx) { numOutputs++; } if (x.instantAcceptanceEscrow) { numOutputs++; } x.outputOrder = lodash_1.default.range(numOutputs); if (!opts.noShuffleOutputs) { x.outputOrder = lodash_1.default.shuffle(x.outputOrder); } x.walletM = opts.walletM; x.walletN = opts.walletN; x.requiredSignatures = x.walletM; (x.requiredRejections = Math.min(x.walletM, x.walletN - x.walletM + 1)), (x.status = 'temporary'); x.actions = []; x.feeLevel = opts.feeLevel; x.feePerKb = opts.feePerKb; x.excludeUnconfirmedUtxos = opts.excludeUnconfirmedUtxos; x.addressType = opts.addressType || (x.walletN > 1 ? Constants.SCRIPT_TYPES.P2SH : Constants.SCRIPT_TYPES.P2PKH); $.checkState(Utils.checkValueInCollection(x.addressType, Constants.SCRIPT_TYPES), 'Failed state: addressType not in ScriptTypes at <create()>'); x.customData = opts.customData; x.amount = opts.amount ? opts.amount : x.getTotalAmount(); x.setInputs(opts.inputs); x.fee = opts.fee; if (x.version === 4) { x.lockUntilBlockHeight = opts.lockUntilBlockHeight; } x.enableRBF = opts.enableRBF; x.replaceTxByFee = opts.replaceTxByFee; x.gasPrice = opts.gasPrice; x.maxGasFee = opts.maxGasFee; x.priorityGasFee = opts.priorityGasFee; x.txType = opts.txType; x.from = opts.from; x.nonce = opts.nonce; x.gasLimit = opts.gasLimit; x.data = opts.data; x.tokenAddress = opts.tokenAddress; x.multiSendContractAddress = opts.multiSendContractAddress; x.isTokenSwap = opts.isTokenSwap; x.multisigContractAddress = opts.multisigContractAddress; x.destinationTag = opts.destinationTag; x.invoiceID = opts.invoiceID; x.multiTx = opts.multiTx; x.space = opts.space; x.blockHash = opts.blockHash; x.blockHeight = opts.blockHeight; x.nonceAddress = opts.nonceAddress; x.category = opts.category; x.computeUnits = opts.computeUnits; x.priorityFee = opts.priorityFee; x.refreshOnPublish = opts.refreshOnPublish; return x; } static fromObj(obj) { if (!(obj.version >= 3)) { return txproposal_legacy_1.TxProposalLegacy.fromObj(obj); } const x = new TxProposal(); x.version = obj.version; x.createdOn = obj.createdOn; x.id = obj.id; x.walletId = obj.walletId; x.creatorId = obj.creatorId; x.coin = obj.coin || Defaults.COIN; x.chain = obj.chain?.toLowerCase() || index_1.ChainService.getChain(x.coin); x.network = obj.network; x.outputs = obj.outputs; x.amount = obj.amount; x.message = obj.message; x.payProUrl = obj.payProUrl; x.changeAddress = obj.changeAddress; x.escrowAddress = obj.escrowAddress; x.instantAcceptanceEscrow = obj.instantAcceptanceEscrow; x.inputs = obj.inputs; x.walletM = obj.walletM; x.walletN = obj.walletN; x.requiredSignatures = obj.requiredSignatures; x.requiredRejections = obj.requiredRejections; x.status = obj.status; x.txid = obj.txid; x.txids = obj.txids; x.broadcastedOn = obj.broadcastedOn; x.inputPaths = obj.inputPaths; x.actions = lodash_1.default.map(obj.actions, action => { return txproposalaction_1.TxProposalAction.fromObj(action); }); x.outputOrder = obj.outputOrder; x.fee = obj.fee; x.feeLevel = obj.feeLevel; x.feePerKb = obj.feePerKb; x.excludeUnconfirmedUtxos = obj.excludeUnconfirmedUtxos; x.addressType = obj.addressType; x.customData = obj.customData; x.proposalSignature = obj.proposalSignature; x.signingMethod = obj.signingMethod; x.proposalSignaturePubKey = obj.proposalSignaturePubKey; x.proposalSignaturePubKeySig = obj.proposalSignaturePubKeySig; x.lockUntilBlockHeight = obj.lockUntilBlockHeight; x.enableRBF = obj.enableRBF; x.replaceTxByFee = obj.replaceTxByFee; x.gasPrice = obj.gasPrice; x.maxGasFee = obj.maxGasFee; x.priorityGasFee = obj.priorityGasFee; x.txType = obj.txType; x.from = obj.from; x.nonce = obj.nonce; x.gasLimit = obj.gasLimit; x.data = obj.data; x.tokenAddress = obj.tokenAddress; x.isTokenSwap = obj.isTokenSwap; x.multiSendContractAddress = obj.multiSendContractAddress; x.multisigContractAddress = obj.multisigContractAddress; x.multisigTxId = obj.multisigTxId; x.destinationTag = obj.destinationTag; x.invoiceID = obj.invoiceID; x.multiTx = obj.multiTx; x.space = obj.space; x.blockHash = obj.blockHash; x.blockHeight = obj.blockHeight; x.nonceAddress = obj.nonceAddress; x.category = obj.category; x.computeUnits = obj.computeUnits; x.priorityFee = obj.priorityFee; x.refreshOnPublish = obj.refreshOnPublish; x.prePublishRaw = obj.prePublishRaw; if (x.status == 'broadcasted') { x.raw = obj.raw; } return x; } toObject() { const x = lodash_1.default.cloneDeep(this); x.isPending = this.isPending(); return x; } setInputs(inputs) { this.inputs = inputs || []; this.inputPaths = lodash_1.default.map(inputs, 'path') || []; } _updateStatus() { if (this.status != 'pending') return; if (this.isRejected()) { this.status = 'rejected'; } else if (this.isAccepted()) { this.status = 'accepted'; } } getCurrentSignatures() { const acceptedActions = lodash_1.default.filter(this.actions, a => { return a.type == 'accept'; }); return lodash_1.default.map(acceptedActions, x => { return { signatures: x.signatures, xpub: x.xpub }; }); } getRawTx() { const t = index_1.ChainService.getBitcoreTx(this); return t.uncheckedSerialize(); } getTotalAmount() { return Number((this.outputs || []).reduce((total, o) => total += BigInt(o.amount), 0n)); } getActors() { return lodash_1.default.map(this.actions, 'copayerId'); } getApprovers() { return lodash_1.default.map(lodash_1.default.filter(this.actions, a => { return a.type == 'accept'; }), 'copayerId'); } getActionBy(copayerId) { return lodash_1.default.find(this.actions, { copayerId }); } addAction(copayerId, type, comment, signatures, xpub) { const action = txproposalaction_1.TxProposalAction.create({ copayerId, type, signatures, xpub, comment }); this.actions.push(action); this._updateStatus(); } sign(copayerId, signatures, xpub) { try { const tx = index_1.ChainService.getBitcoreTx(this); index_1.ChainService.addSignaturesToBitcoreTx(this.chain, tx, this.inputs, this.inputPaths, signatures, xpub, this.signingMethod); this.addAction(copayerId, 'accept', null, signatures, xpub); if (this.status == 'accepted') { this.raw = tx.uncheckedSerialize(); this.txid = tx.id; if (this.multiTx) { this.txids = tx?.txids && tx.txids() || [tx.id]; } } return true; } catch (e) { logger_1.default.debug('%o', e); return false; } } reject(copayerId, reason) { this.addAction(copayerId, 'reject', reason); } isRepublishEnabled() { return !!this.refreshOnPublish; } isTemporary() { return this.status == 'temporary'; } isPending() { return !lodash_1.default.includes(['temporary', 'broadcasted', 'rejected'], this.status); } isAccepted() { const votes = lodash_1.default.countBy(this.actions, 'type'); return votes['accept'] >= this.requiredSignatures; } isRejected() { const votes = lodash_1.default.countBy(this.actions, 'type'); return votes['reject'] >= this.requiredRejections; } isBroadcasted() { return this.status == 'broadcasted'; } setBroadcasted() { $.checkState(this.txid, 'Failed state: this.txid at <setBroadcasted()>'); this.status = 'broadcasted'; this.broadcastedOn = Math.floor(Date.now() / 1000); } } exports.TxProposal = TxProposal; //# sourceMappingURL=txproposal.js.map