UNPKG

meta-contract-debug

Version:

Meta Contract SDK

221 lines (220 loc) 9.46 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Wallet = void 0; const mvc = require("../mvc"); const utils_1 = require("../common/utils"); const api_1 = require("../api"); const tx_composer_1 = require("../tx-composer"); class Wallet { constructor(wif, network = api_1.API_NET.MAIN, feeb, apiTarget = api_1.API_TARGET.MVC, apiUrl) { if (wif) { this.privateKey = mvc.PrivateKey.fromWIF(wif); } else { this.privateKey = mvc.PrivateKey.fromRandom(network); } this.address = this.privateKey.toAddress(network); this.blockChainApi = new api_1.Api(network, apiTarget, apiUrl); this.feeb = feeb; this.network = network; } get api() { return this.blockChainApi; } getUnspents() { return __awaiter(this, void 0, void 0, function* () { return yield this.blockChainApi.getUnspents(this.address.toString()); }); } getUtxos() { return __awaiter(this, void 0, void 0, function* () { return this.getUnspents(); }); } getBalance() { return __awaiter(this, void 0, void 0, function* () { let { pendingBalance, balance } = yield this.blockChainApi.getBalance(this.address.toString()); return balance + pendingBalance; }); } send(address, amount, options) { return __awaiter(this, void 0, void 0, function* () { const txComposer = new tx_composer_1.TxComposer(); let utxos = yield this.blockChainApi.getUnspents(this.address.toString()); const pickedUtxos = this.pickUtxo(utxos, amount); pickedUtxos.forEach((v) => { txComposer.appendP2PKHInput({ address: new mvc.Address(v.address, this.network), txId: v.txId, outputIndex: v.outputIndex, satoshis: v.satoshis, }); }); txComposer.appendP2PKHOutput({ address: new mvc.Address(address, this.network), satoshis: amount, }); txComposer.appendChangeOutput(this.address, this.feeb); pickedUtxos.forEach((v, index) => { txComposer.unlockP2PKHInput(this.privateKey, index); }); return yield this.broadcastTxComposer(txComposer, options); }); } sendArray(receivers, options) { return __awaiter(this, void 0, void 0, function* () { const txComposer = new tx_composer_1.TxComposer(); let utxos = yield this.blockChainApi.getUnspents(this.address.toString()); utxos.forEach((v) => { txComposer.appendP2PKHInput({ address: new mvc.Address(v.address, this.network), txId: v.txId, outputIndex: v.outputIndex, satoshis: v.satoshis, }); }); receivers.forEach((v) => { txComposer.appendP2PKHOutput({ address: new mvc.Address(v.address, this.network), satoshis: v.amount, }); }); txComposer.appendChangeOutput(this.address, this.feeb); utxos.forEach((v, index) => { txComposer.unlockP2PKHInput(this.privateKey, index); }); return yield this.broadcastTxComposer(txComposer, options); }); } merge(options) { return __awaiter(this, void 0, void 0, function* () { const txComposer = new tx_composer_1.TxComposer(); let utxos = yield this.blockChainApi.getUnspents(this.address.toString()); utxos.forEach((v) => { txComposer.appendP2PKHInput({ address: new mvc.Address(v.address, this.network), txId: v.txId, outputIndex: v.outputIndex, satoshis: v.satoshis, }); }); txComposer.appendChangeOutput(this.address, this.feeb); utxos.forEach((v, index) => { txComposer.unlockP2PKHInput(this.privateKey, index); }); return yield this.broadcastTxComposer(txComposer, options); }); } // evenly split all amount into utxo shares, this will increase parallel for wallet // minShareValue is used to guarantee single share value won't be too small // the last share will cover the tx fee evenSplit(shares, minShareValue = 0, options) { return __awaiter(this, void 0, void 0, function* () { const txComposer = new tx_composer_1.TxComposer(); const utxos = yield this.blockChainApi.getUnspents(this.address.toString()); const sumAmount = utxos.map((utxo) => utxo.satoshis).reduce((a, b) => a + b, 0); utxos.forEach((v) => { txComposer.appendP2PKHInput({ address: new mvc.Address(v.address, this.network), txId: v.txId, outputIndex: v.outputIndex, satoshis: v.satoshis, }); }); const shareValue = Math.floor(sumAmount / shares); if (shareValue < minShareValue) { throw new Error(`"Share value ${shareValue} is less than minShareValue ${minShareValue}"`); } for (let i = 0; i < shares - 1; i++) { txComposer.appendP2PKHOutput({ address: this.address, satoshis: shareValue }); } txComposer.appendChangeOutput(this.address, this.feeb); utxos.forEach((v, index) => { txComposer.unlockP2PKHInput(this.privateKey, index); }); return yield this.broadcastTxComposer(txComposer, options); }); } broadcastTxComposer(txComposer, options) { return __awaiter(this, void 0, void 0, function* () { const { noBroadcast, dump } = options || {}; if (dump) { (0, utils_1.dumpTx)(txComposer.getTx(), this.network); } if (noBroadcast) { return txComposer; } return yield this.blockChainApi.broadcast(txComposer.getRawHex()); // return txComposer }); } sendOpReturn(opreturnData, options) { return __awaiter(this, void 0, void 0, function* () { const txComposer = new tx_composer_1.TxComposer(); let utxos = yield this.blockChainApi.getUnspents(this.address.toString()); utxos.forEach((v) => { txComposer.appendP2PKHInput({ address: new mvc.Address(v.address, this.network), txId: v.txId, outputIndex: v.outputIndex, satoshis: v.satoshis, }); }); txComposer.appendOpReturnOutput(opreturnData); txComposer.appendChangeOutput(this.address, this.feeb); utxos.forEach((v, index) => { txComposer.unlockP2PKHInput(this.privateKey, index); }); return yield this.broadcastTxComposer(txComposer, options); }); } // pick utxo enough to pay amount and fee, use confirmed utxo in priority // shuffle confirmed utxo for higher concurrency pickUtxo(utxos, amount) { // amount + 2 outputs + buffer let requiredAmount = amount + 34 * 2 * this.feeb + 100; const candidateUtxos = []; // split utxo to confirmed and unconfirmed and shuffle them const confirmedUtxos = utxos .filter((utxo) => { return utxo.height > 0; }) .sort(() => Math.random() - 0.5); const unconfirmedUtxos = utxos .filter((utxo) => { return utxo.height < 0; }) .sort(() => Math.random() - 0.5); let current = 0; // use confirmed first for (let utxo of confirmedUtxos) { current += utxo.satoshis; // add input fee requiredAmount += this.feeb * utils_1.P2PKH_UNLOCK_SIZE; candidateUtxos.push(utxo); if (current > requiredAmount) { return candidateUtxos; } } for (let utxo of unconfirmedUtxos) { current += utxo.satoshis; // add input fee requiredAmount += this.feeb * utils_1.P2PKH_UNLOCK_SIZE; candidateUtxos.push(utxo); if (current > requiredAmount) { return candidateUtxos; } } return candidateUtxos; } } exports.Wallet = Wallet;